This commit is contained in:
Nikolay Kim 2020-10-05 12:08:26 +06:00
parent 3dd7dc68bd
commit 8bb852aa36
9 changed files with 225 additions and 667 deletions

View file

@ -1,11 +1,9 @@
# Cors Middleware for actix web framework [![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) [![crates.io](https://meritbadge.herokuapp.com/actix-cors)](https://crates.io/crates/actix-cors) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
# Cors Middleware for ntex framework [![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) [![crates.io](https://meritbadge.herokuapp.com/actix-cors)](https://crates.io/crates/actix-cors) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
**This crate moved to https://github.com/actix/actix-extras.**
**This crate moved to https://github.com/ntex/ntex-extras.**
## Documentation & community resources
* [User Guide](https://actix.rs/docs/)
* [API Documentation](https://docs.rs/actix-cors/)
* [Chat on gitter](https://gitter.im/actix/actix)
* Cargo package: [actix-cors](https://crates.io/crates/actix-cors)
* Minimum supported Rust version: 1.34 or later
* [API Documentation](https://docs.rs/ntex-cors/)
* Cargo package: [ntex-cors](https://crates.io/crates/ntex-cors)
* Minimum supported Rust version: 1.42 or later

View file

@ -1,8 +1,4 @@
#![allow(
type_alias_bounds,
clippy::borrow_interior_mutable_const,
clippy::type_complexity
)]
#![allow(type_alias_bounds, clippy::borrow_interior_mutable_const, clippy::type_complexity)]
//! Static files support
use std::fmt::Write;
@ -40,8 +36,7 @@ use self::error::{FilesError, UriSegmentError};
pub use crate::named::NamedFile;
pub use crate::range::HttpRange;
type HttpService<Err: ErrorRenderer> =
BoxService<WebRequest<Err>, WebResponse, Err::Container>;
type HttpService<Err: ErrorRenderer> = BoxService<WebRequest<Err>, WebResponse, Err::Container>;
type HttpServiceFactory<Err: ErrorRenderer> =
BoxServiceFactory<(), WebRequest<Err>, WebResponse, Err::Container, ()>;
@ -60,18 +55,14 @@ pub struct ChunkedReadFile {
size: u64,
offset: u64,
file: Option<File>,
fut:
Option<LocalBoxFuture<'static, Result<(File, Bytes), BlockingError<io::Error>>>>,
fut: Option<LocalBoxFuture<'static, Result<(File, Bytes), BlockingError<io::Error>>>>,
counter: u64,
}
impl Stream for ChunkedReadFile {
type Item = Result<Bytes, std::io::Error>;
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut Context,
) -> Poll<Option<Self::Item>> {
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
if let Some(ref mut fut) = self.fut {
return match Pin::new(fut).poll(cx) {
Poll::Ready(Ok((file, bytes))) => {
@ -108,8 +99,7 @@ impl Stream for ChunkedReadFile {
max_bytes = cmp::min(size.saturating_sub(counter), 65_536) as usize;
let mut buf = Vec::with_capacity(max_bytes);
file.seek(io::SeekFrom::Start(offset))?;
let nbytes =
file.by_ref().take(max_bytes as u64).read_to_end(&mut buf)?;
let nbytes = file.by_ref().take(max_bytes as u64).read_to_end(&mut buf)?;
if nbytes == 0 {
return Err(io::ErrorKind::UnexpectedEof.into());
}
@ -122,8 +112,7 @@ impl Stream for ChunkedReadFile {
}
}
type DirectoryRenderer =
dyn Fn(&Directory, &HttpRequest) -> Result<WebResponse, io::Error>;
type DirectoryRenderer = dyn Fn(&Directory, &HttpRequest) -> Result<WebResponse, io::Error>;
/// A directory; responds with the generated directory listing.
#[derive(Debug)]
@ -171,10 +160,7 @@ macro_rules! encode_file_name {
};
}
fn directory_listing(
dir: &Directory,
req: &HttpRequest,
) -> Result<WebResponse, io::Error> {
fn directory_listing(dir: &Directory, req: &HttpRequest) -> Result<WebResponse, io::Error> {
let index_of = format!("Index of {}", req.path());
let mut body = String::new();
let base = Path::new(req.path());
@ -183,9 +169,7 @@ fn directory_listing(
if dir.is_visible(&entry) {
let entry = entry.unwrap();
let p = match entry.path().strip_prefix(&dir.path) {
Ok(p) if cfg!(windows) => {
base.join(p).to_string_lossy().replace("\\", "/")
}
Ok(p) if cfg!(windows) => base.join(p).to_string_lossy().replace("\\", "/"),
Ok(p) => base.join(p).to_string_lossy().into_owned(),
Err(_) => continue,
};
@ -223,9 +207,7 @@ fn directory_listing(
index_of, index_of, body
);
Ok(WebResponse::new(
HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(html),
HttpResponse::Ok().content_type("text/html; charset=utf-8").body(html),
req.clone(),
))
}
@ -324,8 +306,8 @@ impl<Err: ErrorRenderer> Files<Err> {
/// Set custom directory renderer
pub fn files_listing_renderer<F>(mut self, f: F) -> Self
where
for<'r, 's> F: Fn(&'r Directory, &'s HttpRequest) -> Result<WebResponse, io::Error>
+ 'static,
for<'r, 's> F:
Fn(&'r Directory, &'s HttpRequest) -> Result<WebResponse, io::Error> + 'static,
{
self.renderer = Rc::new(f);
self
@ -397,9 +379,7 @@ impl<Err: ErrorRenderer> Files<Err> {
> + 'static,
{
// create and configure default resource
self.default = Some(Rc::new(boxed::factory(
f.into_factory().map_init_err(|_| ()),
)));
self.default = Some(Rc::new(boxed::factory(f.into_factory().map_init_err(|_| ()))));
self
}
@ -567,10 +547,7 @@ where
named_file.flags = self.file_flags;
let (req, _) = req.into_parts();
Either::Left(ok(WebResponse::new(
named_file.into_response(&req),
req,
)))
Either::Left(ok(WebResponse::new(named_file.into_response(&req), req)))
}
Err(e) => self.handle_io_error(e, req),
}
@ -595,17 +572,13 @@ where
match NamedFile::open(path) {
Ok(mut named_file) => {
if let Some(ref mime_override) = self.mime_override {
let new_disposition =
mime_override(&named_file.content_type.type_());
let new_disposition = mime_override(&named_file.content_type.type_());
named_file.content_disposition.disposition = new_disposition;
}
named_file.flags = self.file_flags;
let (req, _) = req.into_parts();
Either::Left(ok(WebResponse::new(
named_file.into_response(&req),
req,
)))
Either::Left(ok(WebResponse::new(named_file.into_response(&req), req)))
}
Err(e) => self.handle_io_error(e, req),
}
@ -682,9 +655,8 @@ mod tests {
#[ntex::test]
async fn test_if_modified_since_without_if_none_match() {
let file = NamedFile::open("Cargo.toml").unwrap();
let since = hyperx::header::HttpDate::from(
SystemTime::now().add(Duration::from_secs(60)),
);
let since =
hyperx::header::HttpDate::from(SystemTime::now().add(Duration::from_secs(60)));
let req = TestRequest::default()
.header(http::header::IF_MODIFIED_SINCE, since.to_string())
@ -696,9 +668,8 @@ mod tests {
#[ntex::test]
async fn test_if_modified_since_with_if_none_match() {
let file = NamedFile::open("Cargo.toml").unwrap();
let since = hyperx::header::HttpDate::from(
SystemTime::now().add(Duration::from_secs(60)),
);
let since =
hyperx::header::HttpDate::from(SystemTime::now().add(Duration::from_secs(60)));
let req = TestRequest::default()
.header(http::header::IF_NONE_MATCH, "miss_etag")
@ -722,14 +693,9 @@ mod tests {
let req = TestRequest::default().to_http_request();
let resp = test::respond_to(file, &req).await;
assert_eq!(resp.headers().get(http::header::CONTENT_TYPE).unwrap(), "text/x-toml");
assert_eq!(
resp.headers().get(http::header::CONTENT_TYPE).unwrap(),
"text/x-toml"
);
assert_eq!(
resp.headers()
.get(http::header::CONTENT_DISPOSITION)
.unwrap(),
resp.headers().get(http::header::CONTENT_DISPOSITION).unwrap(),
"inline; filename=\"Cargo.toml\""
);
}
@ -749,21 +715,14 @@ mod tests {
let req = TestRequest::default().to_http_request();
let resp = test::respond_to(file, &req).await;
assert_eq!(
resp.headers()
.get(http::header::CONTENT_DISPOSITION)
.unwrap(),
resp.headers().get(http::header::CONTENT_DISPOSITION).unwrap(),
"inline; filename=\"Cargo.toml\""
);
let file = NamedFile::open("Cargo.toml")
.unwrap()
.disable_content_disposition();
let file = NamedFile::open("Cargo.toml").unwrap().disable_content_disposition();
let req = TestRequest::default().to_http_request();
let resp = test::respond_to(file, &req).await;
assert!(resp
.headers()
.get(http::header::CONTENT_DISPOSITION)
.is_none());
assert!(resp.headers().get(http::header::CONTENT_DISPOSITION).is_none());
}
// #[ntex::test]
@ -795,9 +754,7 @@ mod tests {
#[ntex::test]
async fn test_named_file_set_content_type() {
let mut file = NamedFile::open("Cargo.toml")
.unwrap()
.set_content_type(mime::TEXT_XML);
let mut file = NamedFile::open("Cargo.toml").unwrap().set_content_type(mime::TEXT_XML);
{
file.file();
let _f: &File = &file;
@ -808,14 +765,9 @@ mod tests {
let req = TestRequest::default().to_http_request();
let resp = test::respond_to(file, &req).await;
assert_eq!(resp.headers().get(http::header::CONTENT_TYPE).unwrap(), "text/xml");
assert_eq!(
resp.headers().get(http::header::CONTENT_TYPE).unwrap(),
"text/xml"
);
assert_eq!(
resp.headers()
.get(http::header::CONTENT_DISPOSITION)
.unwrap(),
resp.headers().get(http::header::CONTENT_DISPOSITION).unwrap(),
"inline; filename=\"Cargo.toml\""
);
}
@ -833,23 +785,16 @@ mod tests {
let req = TestRequest::default().to_http_request();
let resp = test::respond_to(file, &req).await;
assert_eq!(resp.headers().get(http::header::CONTENT_TYPE).unwrap(), "image/png");
assert_eq!(
resp.headers().get(http::header::CONTENT_TYPE).unwrap(),
"image/png"
);
assert_eq!(
resp.headers()
.get(http::header::CONTENT_DISPOSITION)
.unwrap(),
resp.headers().get(http::header::CONTENT_DISPOSITION).unwrap(),
"inline; filename=\"test.png\""
);
}
#[ntex::test]
async fn test_named_file_image_attachment() {
use hyperx::header::{
Charset, ContentDisposition, DispositionParam, DispositionType,
};
use hyperx::header::{Charset, ContentDisposition, DispositionParam, DispositionType};
let cd = ContentDisposition {
disposition: DispositionType::Attachment,
@ -859,9 +804,7 @@ mod tests {
"test.png".to_string().into_bytes(),
)],
};
let mut file = NamedFile::open("tests/test.png")
.unwrap()
.set_content_disposition(cd);
let mut file = NamedFile::open("tests/test.png").unwrap().set_content_disposition(cd);
{
file.file();
let _f: &File = &file;
@ -872,14 +815,9 @@ mod tests {
let req = TestRequest::default().to_http_request();
let resp = test::respond_to(file, &req).await;
assert_eq!(resp.headers().get(http::header::CONTENT_TYPE).unwrap(), "image/png");
assert_eq!(
resp.headers().get(http::header::CONTENT_TYPE).unwrap(),
"image/png"
);
assert_eq!(
resp.headers()
.get(http::header::CONTENT_DISPOSITION)
.unwrap(),
resp.headers().get(http::header::CONTENT_DISPOSITION).unwrap(),
"attachment; filename=\"test.png\""
);
}
@ -902,18 +840,15 @@ mod tests {
"application/octet-stream"
);
assert_eq!(
resp.headers()
.get(http::header::CONTENT_DISPOSITION)
.unwrap(),
resp.headers().get(http::header::CONTENT_DISPOSITION).unwrap(),
"attachment; filename=\"test.binary\""
);
}
#[ntex::test]
async fn test_named_file_status_code_text() {
let mut file = NamedFile::open("Cargo.toml")
.unwrap()
.set_status_code(StatusCode::NOT_FOUND);
let mut file =
NamedFile::open("Cargo.toml").unwrap().set_status_code(StatusCode::NOT_FOUND);
{
file.file();
let _f: &File = &file;
@ -924,14 +859,9 @@ mod tests {
let req = TestRequest::default().to_http_request();
let resp = test::respond_to(file, &req).await;
assert_eq!(resp.headers().get(http::header::CONTENT_TYPE).unwrap(), "text/x-toml");
assert_eq!(
resp.headers().get(http::header::CONTENT_TYPE).unwrap(),
"text/x-toml"
);
assert_eq!(
resp.headers()
.get(http::header::CONTENT_DISPOSITION)
.unwrap(),
resp.headers().get(http::header::CONTENT_DISPOSITION).unwrap(),
"inline; filename=\"Cargo.toml\""
);
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
@ -943,13 +873,9 @@ mod tests {
DispositionType::Attachment
}
let mut srv = test::init_service(
App::new().service(
Files::new("/", ".")
.mime_override(all_attachment)
.index_file("Cargo.toml"),
),
)
let mut srv = test::init_service(App::new().service(
Files::new("/", ".").mime_override(all_attachment).index_file("Cargo.toml"),
))
.await;
let request = TestRequest::get().uri("/").to_request();
@ -960,9 +886,8 @@ mod tests {
.headers()
.get(http::header::CONTENT_DISPOSITION)
.expect("To have CONTENT_DISPOSITION");
let content_disposition = content_disposition
.to_str()
.expect("Convert CONTENT_DISPOSITION to str");
let content_disposition =
content_disposition.to_str().expect("Convert CONTENT_DISPOSITION to str");
assert_eq!(content_disposition, "attachment; filename=\"Cargo.toml\"");
}
@ -1005,12 +930,8 @@ mod tests {
.to_request();
let response = test::call_service(&mut srv, request).await;
let contentrange = response
.headers()
.get(http::header::CONTENT_RANGE)
.unwrap()
.to_str()
.unwrap();
let contentrange =
response.headers().get(http::header::CONTENT_RANGE).unwrap().to_str().unwrap();
assert_eq!(contentrange, "bytes 10-20/100");
@ -1021,12 +942,8 @@ mod tests {
.to_request();
let response = test::call_service(&mut srv, request).await;
let contentrange = response
.headers()
.get(http::header::CONTENT_RANGE)
.unwrap()
.to_str()
.unwrap();
let contentrange =
response.headers().get(http::header::CONTENT_RANGE).unwrap().to_str().unwrap();
assert_eq!(contentrange, "bytes */100");
}
@ -1077,9 +994,7 @@ mod tests {
// assert_eq!(contentlength, "100");
// chunked
let request = TestRequest::get()
.uri("/t%65st/tests/test.binary")
.to_request();
let request = TestRequest::get().uri("/t%65st/tests/test.binary").to_request();
let response = test::call_service(&mut srv, request).await;
// with enabled compression
@ -1128,9 +1043,7 @@ mod tests {
App::new().service(Files::new("/", ".").index_file("Cargo.toml")),
)
.await;
let request = TestRequest::get()
.uri("/tests/test%20space.binary")
.to_request();
let request = TestRequest::get().uri("/tests/test%20space.binary").to_request();
let response = test::call_service(&srv, request).await;
assert_eq!(response.status(), StatusCode::OK);
@ -1143,19 +1056,13 @@ mod tests {
async fn test_files_not_allowed() {
let mut srv = test::init_service(App::new().service(Files::new("/", "."))).await;
let req = TestRequest::default()
.uri("/Cargo.toml")
.method(Method::POST)
.to_request();
let req = TestRequest::default().uri("/Cargo.toml").method(Method::POST).to_request();
let resp = test::call_service(&mut srv, req).await;
assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED);
let mut srv = test::init_service(App::new().service(Files::new("/", "."))).await;
let req = TestRequest::default()
.method(Method::PUT)
.uri("/Cargo.toml")
.to_request();
let req = TestRequest::default().method(Method::PUT).uri("/Cargo.toml").to_request();
let resp = test::call_service(&mut srv, req).await;
assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED);
}
@ -1167,10 +1074,7 @@ mod tests {
)
.await;
let req = TestRequest::default()
.uri("/Cargo.toml")
.method(Method::POST)
.to_request();
let req = TestRequest::default().uri("/Cargo.toml").method(Method::POST).to_request();
let resp = test::call_service(&mut srv, req).await;
assert_eq!(resp.status(), StatusCode::OK);
@ -1214,11 +1118,7 @@ mod tests {
let res = test::call_service(&mut srv, request).await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.headers()
.get(http::header::CONTENT_ENCODING)
.unwrap()
.to_str()
.unwrap(),
res.headers().get(http::header::CONTENT_ENCODING).unwrap().to_str().unwrap(),
"gzip"
);
}
@ -1233,10 +1133,9 @@ mod tests {
#[ntex::test]
async fn test_static_files() {
let mut srv = test::init_service(
App::new().service(Files::new("/", ".").show_files_listing()),
)
.await;
let mut srv =
test::init_service(App::new().service(Files::new("/", ".").show_files_listing()))
.await;
let req = TestRequest::with_uri("/missing").to_request();
let resp = test::call_service(&mut srv, req).await;
@ -1248,10 +1147,9 @@ mod tests {
let resp = test::call_service(&mut srv, req).await;
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
let mut srv = test::init_service(
App::new().service(Files::new("/", ".").show_files_listing()),
)
.await;
let mut srv =
test::init_service(App::new().service(Files::new("/", ".").show_files_listing()))
.await;
let req = TestRequest::with_uri("/tests").to_request();
let resp = test::call_service(&mut srv, req).await;
assert_eq!(
@ -1275,13 +1173,9 @@ mod tests {
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
// should redirect if index present
let mut srv = test::init_service(
App::new().service(
Files::new("/", ".")
.index_file("test.png")
.redirect_to_slash_directory(),
),
)
let mut srv = test::init_service(App::new().service(
Files::new("/", ".").index_file("test.png").redirect_to_slash_directory(),
))
.await;
let req = TestRequest::with_uri("/tests").to_request();
let resp = test::call_service(&mut srv, req).await;

View file

@ -100,10 +100,7 @@ impl NamedFile {
None,
filename.into_owned().into_bytes(),
)];
let cd = ContentDisposition {
disposition,
parameters,
};
let cd = ContentDisposition { disposition, parameters };
(ct, cd)
};
@ -256,13 +253,15 @@ impl NamedFile {
pub fn into_response(self, req: &HttpRequest) -> HttpResponse {
if self.status_code != StatusCode::OK {
let mut resp = HttpResponse::build(self.status_code);
resp.header(http::header::CONTENT_TYPE, self.content_type.to_string())
.if_true(self.flags.contains(Flags::CONTENT_DISPOSITION), |res| {
resp.header(http::header::CONTENT_TYPE, self.content_type.to_string()).if_true(
self.flags.contains(Flags::CONTENT_DISPOSITION),
|res| {
res.header(
http::header::CONTENT_DISPOSITION,
self.content_disposition.to_string(),
);
});
},
);
if let Some(current_encoding) = self.encoding {
resp.encoding(current_encoding);
}
@ -276,16 +275,9 @@ impl NamedFile {
return resp.streaming(reader);
}
let etag = if self.flags.contains(Flags::ETAG) {
self.etag()
} else {
None
};
let last_modified = if self.flags.contains(Flags::LAST_MD) {
self.last_modified()
} else {
None
};
let etag = if self.flags.contains(Flags::ETAG) { self.etag() } else { None };
let last_modified =
if self.flags.contains(Flags::LAST_MD) { self.last_modified() } else { None };
// check preconditions
let precondition_failed = if !any_match(etag.as_ref(), req) {
@ -293,9 +285,9 @@ impl NamedFile {
} else if let (Some(ref m), Some(header::IfUnmodifiedSince(ref since))) = {
let mut header = None;
for hdr in req.headers().get_all(http::header::IF_UNMODIFIED_SINCE) {
if let Ok(v) = header::IfUnmodifiedSince::parse_header(
&header::Raw::from(hdr.as_bytes()),
) {
if let Ok(v) =
header::IfUnmodifiedSince::parse_header(&header::Raw::from(hdr.as_bytes()))
{
header = Some(v);
break;
}
@ -321,9 +313,9 @@ impl NamedFile {
} else if let (Some(ref m), Some(header::IfModifiedSince(ref since))) = {
let mut header = None;
for hdr in req.headers().get_all(http::header::IF_MODIFIED_SINCE) {
if let Ok(v) = header::IfModifiedSince::parse_header(&header::Raw::from(
hdr.as_bytes(),
)) {
if let Ok(v) =
header::IfModifiedSince::parse_header(&header::Raw::from(hdr.as_bytes()))
{
header = Some(v);
break;
}
@ -341,23 +333,22 @@ impl NamedFile {
};
let mut resp = HttpResponse::build(self.status_code);
resp.header(http::header::CONTENT_TYPE, self.content_type.to_string())
.if_true(self.flags.contains(Flags::CONTENT_DISPOSITION), |res| {
resp.header(http::header::CONTENT_TYPE, self.content_type.to_string()).if_true(
self.flags.contains(Flags::CONTENT_DISPOSITION),
|res| {
res.header(
http::header::CONTENT_DISPOSITION,
self.content_disposition.to_string(),
);
});
},
);
// default compressing
if let Some(current_encoding) = self.encoding {
resp.encoding(current_encoding);
}
resp.if_some(last_modified, |lm, resp| {
resp.header(
http::header::LAST_MODIFIED,
header::LastModified(lm).to_string(),
);
resp.header(http::header::LAST_MODIFIED, header::LastModified(lm).to_string());
})
.if_some(etag, |etag, resp| {
resp.header(http::header::ETAG, header::ETag(etag).to_string());
@ -377,18 +368,10 @@ impl NamedFile {
resp.encoding(ContentEncoding::Identity);
resp.header(
http::header::CONTENT_RANGE,
format!(
"bytes {}-{}/{}",
offset,
offset + length - 1,
self.md.len()
),
format!("bytes {}-{}/{}", offset, offset + length - 1, self.md.len()),
);
} else {
resp.header(
http::header::CONTENT_RANGE,
format!("bytes */{}", length),
);
resp.header(http::header::CONTENT_RANGE, format!("bytes */{}", length));
return resp.status(StatusCode::RANGE_NOT_SATISFIABLE).finish();
};
} else {

View file

@ -75,10 +75,7 @@ impl HttpRange {
end - start + 1
};
Ok(Some(HttpRange {
start: start as u64,
length: length as u64,
}))
Ok(Some(HttpRange { start: start as u64, length: length as u64 }))
}
})
.collect::<Result<_, _>>()?;
@ -122,180 +119,55 @@ mod tests {
T("bytes=0x01-0x02", 10, vec![]),
T("bytes= ", 10, vec![]),
T("bytes= , , , ", 10, vec![]),
T(
"bytes=0-9",
10,
vec![HttpRange {
start: 0,
length: 10,
}],
),
T(
"bytes=0-",
10,
vec![HttpRange {
start: 0,
length: 10,
}],
),
T(
"bytes=5-",
10,
vec![HttpRange {
start: 5,
length: 5,
}],
),
T(
"bytes=0-20",
10,
vec![HttpRange {
start: 0,
length: 10,
}],
),
T(
"bytes=15-,0-5",
10,
vec![HttpRange {
start: 0,
length: 6,
}],
),
T("bytes=0-9", 10, vec![HttpRange { start: 0, length: 10 }]),
T("bytes=0-", 10, vec![HttpRange { start: 0, length: 10 }]),
T("bytes=5-", 10, vec![HttpRange { start: 5, length: 5 }]),
T("bytes=0-20", 10, vec![HttpRange { start: 0, length: 10 }]),
T("bytes=15-,0-5", 10, vec![HttpRange { start: 0, length: 6 }]),
T(
"bytes=1-2,5-",
10,
vec![
HttpRange {
start: 1,
length: 2,
},
HttpRange {
start: 5,
length: 5,
},
],
vec![HttpRange { start: 1, length: 2 }, HttpRange { start: 5, length: 5 }],
),
T(
"bytes=-2 , 7-",
11,
vec![
HttpRange {
start: 9,
length: 2,
},
HttpRange {
start: 7,
length: 4,
},
],
vec![HttpRange { start: 9, length: 2 }, HttpRange { start: 7, length: 4 }],
),
T(
"bytes=0-0 ,2-2, 7-",
11,
vec![
HttpRange {
start: 0,
length: 1,
},
HttpRange {
start: 2,
length: 1,
},
HttpRange {
start: 7,
length: 4,
},
HttpRange { start: 0, length: 1 },
HttpRange { start: 2, length: 1 },
HttpRange { start: 7, length: 4 },
],
),
T(
"bytes=-5",
10,
vec![HttpRange {
start: 5,
length: 5,
}],
),
T(
"bytes=-15",
10,
vec![HttpRange {
start: 0,
length: 10,
}],
),
T(
"bytes=0-499",
10000,
vec![HttpRange {
start: 0,
length: 500,
}],
),
T(
"bytes=500-999",
10000,
vec![HttpRange {
start: 500,
length: 500,
}],
),
T(
"bytes=-500",
10000,
vec![HttpRange {
start: 9500,
length: 500,
}],
),
T(
"bytes=9500-",
10000,
vec![HttpRange {
start: 9500,
length: 500,
}],
),
T("bytes=-5", 10, vec![HttpRange { start: 5, length: 5 }]),
T("bytes=-15", 10, vec![HttpRange { start: 0, length: 10 }]),
T("bytes=0-499", 10000, vec![HttpRange { start: 0, length: 500 }]),
T("bytes=500-999", 10000, vec![HttpRange { start: 500, length: 500 }]),
T("bytes=-500", 10000, vec![HttpRange { start: 9500, length: 500 }]),
T("bytes=9500-", 10000, vec![HttpRange { start: 9500, length: 500 }]),
T(
"bytes=0-0,-1",
10000,
vec![
HttpRange {
start: 0,
length: 1,
},
HttpRange {
start: 9999,
length: 1,
},
],
vec![HttpRange { start: 0, length: 1 }, HttpRange { start: 9999, length: 1 }],
),
T(
"bytes=500-600,601-999",
10000,
vec![
HttpRange {
start: 500,
length: 101,
},
HttpRange {
start: 601,
length: 399,
},
HttpRange { start: 500, length: 101 },
HttpRange { start: 601, length: 399 },
],
),
T(
"bytes=500-700,601-999",
10000,
vec![
HttpRange {
start: 500,
length: 201,
},
HttpRange {
start: 601,
length: 399,
},
HttpRange { start: 500, length: 201 },
HttpRange { start: 601, length: 399 },
],
),
// Match Apache laxity:
@ -303,18 +175,9 @@ mod tests {
"bytes= 1 -2 , 4- 5, 7 - 8 , ,,",
11,
vec![
HttpRange {
start: 1,
length: 2,
},
HttpRange {
start: 4,
length: 2,
},
HttpRange {
start: 7,
length: 2,
},
HttpRange { start: 1, length: 2 },
HttpRange { start: 4, length: 2 },
HttpRange { start: 7, length: 2 },
],
),
];

View file

@ -62,9 +62,7 @@ use ntex::http::header::{self, HeaderValue};
use ntex::http::{Extensions, HttpMessage, Payload};
use ntex::service::{Service, Transform};
use ntex::web::dev::{WebRequest, WebResponse};
use ntex::web::{
DefaultError, ErrorRenderer, FromRequest, HttpRequest, WebResponseError,
};
use ntex::web::{DefaultError, ErrorRenderer, FromRequest, HttpRequest, WebResponseError};
/// The extractor type to obtain your identity from a request.
///
@ -219,10 +217,7 @@ pub struct IdentityService<T, Err> {
impl<T, Err> IdentityService<T, Err> {
/// Create new identity service with specified backend.
pub fn new(backend: T) -> Self {
IdentityService {
backend: Rc::new(backend),
_t: PhantomData,
}
IdentityService { backend: Rc::new(backend), _t: PhantomData }
}
}
@ -260,11 +255,7 @@ pub struct IdentityServiceMiddleware<S, T, Err> {
impl<S, T, Err> Clone for IdentityServiceMiddleware<S, T, Err> {
fn clone(&self) -> Self {
Self {
backend: self.backend.clone(),
service: self.service.clone(),
_t: PhantomData,
}
Self { backend: self.backend.clone(), service: self.service.clone(), _t: PhantomData }
}
}
@ -298,8 +289,7 @@ where
async move {
match fut.await {
Ok(id) => {
req.extensions_mut()
.insert(IdentityItem { id, changed: false });
req.extensions_mut().insert(IdentityItem { id, changed: false });
// https://github.com/actix/actix-web/issues/1263
let fut = { srv.call(req) };
@ -400,11 +390,7 @@ impl<Err: ErrorRenderer> CookieIdentityInner<Err> {
}
let mut jar = CookieJar::new();
let key = if self.legacy_supported() {
&self.key
} else {
&self.key_v2
};
let key = if self.legacy_supported() { &self.key } else { &self.key_v2 };
if add_cookie {
jar.private(&key).add(cookie);
} else {
@ -412,8 +398,7 @@ impl<Err: ErrorRenderer> CookieIdentityInner<Err> {
jar.private(&key).remove(cookie);
}
for cookie in jar.delta() {
let val =
HeaderValue::from_str(&cookie.to_string()).map_err(HttpError::from)?;
let val = HeaderValue::from_str(&cookie.to_string()).map_err(HttpError::from)?;
resp.headers_mut().append(header::SET_COOKIE, val);
}
Ok(())
@ -432,11 +417,7 @@ impl<Err: ErrorRenderer> CookieIdentityInner<Err> {
} else {
None
};
res.or_else(|| {
jar.private(&self.key_v2)
.get(&self.name)
.and_then(|c| self.parse(c))
})
res.or_else(|| jar.private(&self.key_v2).get(&self.name).and_then(|c| self.parse(c)))
}
fn parse(&self, cookie: Cookie) -> Option<CookieValue> {
@ -575,19 +556,12 @@ impl<Err: ErrorRenderer> IdentityPolicy<Err> for CookieIdentityPolicy<Err> {
type ResponseFuture = Ready<Result<(), CookieIdentityPolicyError>>;
fn from_request(&self, req: &mut WebRequest<Err>) -> Self::Future {
ok(self.0.load(req).map(
|CookieValue {
identity,
login_timestamp,
..
}| {
if self.0.requires_oob_data() {
req.extensions_mut()
.insert(CookieIdentityExtention { login_timestamp });
}
identity
},
))
ok(self.0.load(req).map(|CookieValue { identity, login_timestamp, .. }| {
if self.0.requires_oob_data() {
req.extensions_mut().insert(CookieIdentityExtention { login_timestamp });
}
identity
}))
}
fn to_response(
@ -609,9 +583,8 @@ impl<Err: ErrorRenderer> IdentityPolicy<Err> for CookieIdentityPolicy<Err> {
} else if self.0.always_update_cookie() && id.is_some() {
let visit_timestamp = SystemTime::now();
let login_timestamp = if self.0.requires_oob_data() {
let CookieIdentityExtention {
login_timestamp: lt,
} = res.request().extensions_mut().remove().unwrap();
let CookieIdentityExtention { login_timestamp: lt } =
res.request().extensions_mut().remove().unwrap();
lt
} else {
None
@ -678,30 +651,24 @@ mod tests {
)
.await;
let resp =
test::call_service(&mut srv, TestRequest::with_uri("/index").to_request())
.await;
test::call_service(&mut srv, TestRequest::with_uri("/index").to_request()).await;
assert_eq!(resp.status(), StatusCode::OK);
let resp =
test::call_service(&mut srv, TestRequest::with_uri("/login").to_request())
.await;
test::call_service(&mut srv, TestRequest::with_uri("/login").to_request()).await;
assert_eq!(resp.status(), StatusCode::OK);
let c = resp.response().cookies().next().unwrap().to_owned();
let resp = test::call_service(
&mut srv,
TestRequest::with_uri("/index")
.cookie(c.clone())
.to_request(),
TestRequest::with_uri("/index").cookie(c.clone()).to_request(),
)
.await;
assert_eq!(resp.status(), StatusCode::CREATED);
let resp = test::call_service(
&mut srv,
TestRequest::with_uri("/logout")
.cookie(c.clone())
.to_request(),
TestRequest::with_uri("/logout").cookie(c.clone()).to_request(),
)
.await;
assert_eq!(resp.status(), StatusCode::OK);
@ -728,8 +695,7 @@ mod tests {
)
.await;
let resp =
test::call_service(&mut srv, TestRequest::with_uri("/login").to_request())
.await;
test::call_service(&mut srv, TestRequest::with_uri("/login").to_request()).await;
assert_eq!(resp.status(), StatusCode::OK);
assert!(resp.headers().contains_key(header::SET_COOKIE));
let c = resp.response().cookies().next().unwrap().to_owned();
@ -756,8 +722,7 @@ mod tests {
)
.await;
let resp =
test::call_service(&mut srv, TestRequest::with_uri("/login").to_request())
.await;
test::call_service(&mut srv, TestRequest::with_uri("/login").to_request()).await;
assert_eq!(resp.status(), StatusCode::OK);
assert!(resp.headers().contains_key(header::SET_COOKIE));
let c = resp.response().cookies().next().unwrap().to_owned();
@ -779,11 +744,9 @@ mod tests {
> {
test::init_service(
App::new()
.wrap(IdentityService::new(f(CookieIdentityPolicy::new(
&COOKIE_KEY_MASTER,
)
.secure(false)
.name(COOKIE_NAME))))
.wrap(IdentityService::new(f(CookieIdentityPolicy::new(&COOKIE_KEY_MASTER)
.secure(false)
.name(COOKIE_NAME))))
.service(web::resource("/").to(|id: Identity| async move {
let identity = id.identity();
if identity.is_none() {
@ -808,11 +771,8 @@ mod tests {
visit_timestamp: Option<SystemTime>,
) -> Cookie<'static> {
let mut jar = CookieJar::new();
let key: Vec<u8> = COOKIE_KEY_MASTER
.iter()
.chain([1, 0, 0, 0].iter())
.map(|e| *e)
.collect();
let key: Vec<u8> =
COOKIE_KEY_MASTER.iter().chain([1, 0, 0, 0].iter()).map(|e| *e).collect();
jar.private(&Key::derive_from(&key)).add(Cookie::new(
COOKIE_NAME,
serde_json::to_string(&CookieValue {
@ -836,10 +796,8 @@ mod tests {
for cookie in response.headers().get_all(header::SET_COOKIE) {
cookies.add(Cookie::parse(cookie.to_str().unwrap().to_string()).unwrap());
}
let cookie = cookies
.private(&Key::derive_from(&COOKIE_KEY_MASTER))
.get(COOKIE_NAME)
.unwrap();
let cookie =
cookies.private(&Key::derive_from(&COOKIE_KEY_MASTER)).get(COOKIE_NAME).unwrap();
assert_eq!(cookie.value(), identity);
}
@ -864,15 +822,9 @@ mod tests {
for cookie in response.headers().get_all(header::SET_COOKIE) {
cookies.add(Cookie::parse(cookie.to_str().unwrap().to_string()).unwrap());
}
let key: Vec<u8> = COOKIE_KEY_MASTER
.iter()
.chain([1, 0, 0, 0].iter())
.map(|e| *e)
.collect();
let cookie = cookies
.private(&Key::derive_from(&key))
.get(COOKIE_NAME)
.unwrap();
let key: Vec<u8> =
COOKIE_KEY_MASTER.iter().chain([1, 0, 0, 0].iter()).map(|e| *e).collect();
let cookie = cookies.private(&Key::derive_from(&key)).get(COOKIE_NAME).unwrap();
let cv: CookieValue = serde_json::from_str(cookie.value()).unwrap();
assert_eq!(cv.identity, identity);
let now = SystemTime::now();
@ -880,8 +832,7 @@ mod tests {
match login_timestamp {
LoginTimestampCheck::NoTimestamp => assert_eq!(cv.login_timestamp, None),
LoginTimestampCheck::NewTimestamp => assert!(
t30sec_ago <= cv.login_timestamp.unwrap()
&& cv.login_timestamp.unwrap() <= now
t30sec_ago <= cv.login_timestamp.unwrap() && cv.login_timestamp.unwrap() <= now
),
LoginTimestampCheck::OldTimestamp(old_timestamp) => {
assert_eq!(cv.login_timestamp, Some(old_timestamp))
@ -890,8 +841,7 @@ mod tests {
match visit_timestamp {
VisitTimeStampCheck::NoTimestamp => assert_eq!(cv.visit_timestamp, None),
VisitTimeStampCheck::NewTimestamp => assert!(
t30sec_ago <= cv.visit_timestamp.unwrap()
&& cv.visit_timestamp.unwrap() <= now
t30sec_ago <= cv.visit_timestamp.unwrap() && cv.visit_timestamp.unwrap() <= now
),
}
}
@ -919,9 +869,7 @@ mod tests {
let cookie = legacy_login_cookie(COOKIE_LOGIN);
let mut resp = test::call_service(
&mut srv,
TestRequest::with_uri("/")
.cookie(cookie.clone())
.to_request(),
TestRequest::with_uri("/").cookie(cookie.clone()).to_request(),
)
.await;
assert_no_login_cookie(&mut resp);
@ -930,14 +878,11 @@ mod tests {
#[ntex::test]
async fn test_identity_legacy_cookie_rejected_if_visit_timestamp_needed() {
let mut srv =
create_identity_server(|c| c.visit_deadline(Duration::days(90))).await;
let mut srv = create_identity_server(|c| c.visit_deadline(Duration::days(90))).await;
let cookie = legacy_login_cookie(COOKIE_LOGIN);
let mut resp = test::call_service(
&mut srv,
TestRequest::with_uri("/")
.cookie(cookie.clone())
.to_request(),
TestRequest::with_uri("/").cookie(cookie.clone()).to_request(),
)
.await;
assert_login_cookie(
@ -951,14 +896,11 @@ mod tests {
#[ntex::test]
async fn test_identity_legacy_cookie_rejected_if_login_timestamp_needed() {
let mut srv =
create_identity_server(|c| c.login_deadline(Duration::days(90))).await;
let mut srv = create_identity_server(|c| c.login_deadline(Duration::days(90))).await;
let cookie = legacy_login_cookie(COOKIE_LOGIN);
let mut resp = test::call_service(
&mut srv,
TestRequest::with_uri("/")
.cookie(cookie.clone())
.to_request(),
TestRequest::with_uri("/").cookie(cookie.clone()).to_request(),
)
.await;
assert_login_cookie(
@ -972,14 +914,11 @@ mod tests {
#[ntex::test]
async fn test_identity_cookie_rejected_if_login_timestamp_needed() {
let mut srv =
create_identity_server(|c| c.login_deadline(Duration::days(90))).await;
let mut srv = create_identity_server(|c| c.login_deadline(Duration::days(90))).await;
let cookie = login_cookie(COOKIE_LOGIN, None, Some(SystemTime::now()));
let mut resp = test::call_service(
&mut srv,
TestRequest::with_uri("/")
.cookie(cookie.clone())
.to_request(),
TestRequest::with_uri("/").cookie(cookie.clone()).to_request(),
)
.await;
assert_login_cookie(
@ -993,14 +932,11 @@ mod tests {
#[ntex::test]
async fn test_identity_cookie_rejected_if_visit_timestamp_needed() {
let mut srv =
create_identity_server(|c| c.visit_deadline(Duration::days(90))).await;
let mut srv = create_identity_server(|c| c.visit_deadline(Duration::days(90))).await;
let cookie = login_cookie(COOKIE_LOGIN, Some(SystemTime::now()), None);
let mut resp = test::call_service(
&mut srv,
TestRequest::with_uri("/")
.cookie(cookie.clone())
.to_request(),
TestRequest::with_uri("/").cookie(cookie.clone()).to_request(),
)
.await;
assert_login_cookie(
@ -1014,18 +950,12 @@ mod tests {
#[ntex::test]
async fn test_identity_cookie_rejected_if_login_timestamp_too_old() {
let mut srv =
create_identity_server(|c| c.login_deadline(Duration::days(90))).await;
let cookie = login_cookie(
COOKIE_LOGIN,
Some(SystemTime::now() - Duration::days(180)),
None,
);
let mut srv = create_identity_server(|c| c.login_deadline(Duration::days(90))).await;
let cookie =
login_cookie(COOKIE_LOGIN, Some(SystemTime::now() - Duration::days(180)), None);
let mut resp = test::call_service(
&mut srv,
TestRequest::with_uri("/")
.cookie(cookie.clone())
.to_request(),
TestRequest::with_uri("/").cookie(cookie.clone()).to_request(),
)
.await;
assert_login_cookie(
@ -1039,18 +969,12 @@ mod tests {
#[ntex::test]
async fn test_identity_cookie_rejected_if_visit_timestamp_too_old() {
let mut srv =
create_identity_server(|c| c.visit_deadline(Duration::days(90))).await;
let cookie = login_cookie(
COOKIE_LOGIN,
None,
Some(SystemTime::now() - Duration::days(180)),
);
let mut srv = create_identity_server(|c| c.visit_deadline(Duration::days(90))).await;
let cookie =
login_cookie(COOKIE_LOGIN, None, Some(SystemTime::now() - Duration::days(180)));
let mut resp = test::call_service(
&mut srv,
TestRequest::with_uri("/")
.cookie(cookie.clone())
.to_request(),
TestRequest::with_uri("/").cookie(cookie.clone()).to_request(),
)
.await;
assert_login_cookie(
@ -1064,14 +988,11 @@ mod tests {
#[ntex::test]
async fn test_identity_cookie_not_updated_on_login_deadline() {
let mut srv =
create_identity_server(|c| c.login_deadline(Duration::days(90))).await;
let mut srv = create_identity_server(|c| c.login_deadline(Duration::days(90))).await;
let cookie = login_cookie(COOKIE_LOGIN, Some(SystemTime::now()), None);
let mut resp = test::call_service(
&mut srv,
TestRequest::with_uri("/")
.cookie(cookie.clone())
.to_request(),
TestRequest::with_uri("/").cookie(cookie.clone()).to_request(),
)
.await;
assert_no_login_cookie(&mut resp);
@ -1082,17 +1003,14 @@ mod tests {
#[ntex::test]
async fn test_identity_cookie_updated_on_visit_deadline() {
let mut srv = create_identity_server(|c| {
c.visit_deadline(Duration::days(90))
.login_deadline(Duration::days(90))
c.visit_deadline(Duration::days(90)).login_deadline(Duration::days(90))
})
.await;
let timestamp = SystemTime::now() - Duration::days(1);
let cookie = login_cookie(COOKIE_LOGIN, Some(timestamp), Some(timestamp));
let mut resp = test::call_service(
&mut srv,
TestRequest::with_uri("/")
.cookie(cookie.clone())
.to_request(),
TestRequest::with_uri("/").cookie(cookie.clone()).to_request(),
)
.await;
assert_login_cookie(

View file

@ -71,11 +71,7 @@ impl Multipart {
item: InnerMultipartItem::None,
}))),
},
Err(err) => Multipart {
error: Some(err),
safety: Safety::new(),
inner: None,
},
Err(err) => Multipart { error: Some(err), safety: Safety::new(), inner: None },
}
}
@ -104,10 +100,7 @@ impl Multipart {
impl Stream for Multipart {
type Item = Result<Field, MultipartError>;
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut Context,
) -> Poll<Option<Self::Item>> {
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
if let Some(err) = self.error.take() {
Poll::Ready(Some(Err(err)))
} else if self.safety.current() {
@ -126,9 +119,7 @@ impl Stream for Multipart {
}
impl InnerMultipart {
fn read_headers(
payload: &mut PayloadBuffer,
) -> Result<Option<HeaderMap>, MultipartError> {
fn read_headers(payload: &mut PayloadBuffer) -> Result<Option<HeaderMap>, MultipartError> {
match payload.read_until(b"\r\n\r\n")? {
None => {
if payload.eof {
@ -210,8 +201,7 @@ impl InnerMultipart {
if chunk.len() < boundary.len() {
continue;
}
if &chunk[..2] == b"--"
&& &chunk[2..chunk.len() - 2] == boundary.as_bytes()
if &chunk[..2] == b"--" && &chunk[2..chunk.len() - 2] == boundary.as_bytes()
{
break;
} else {
@ -257,9 +247,7 @@ impl InnerMultipart {
match field.borrow_mut().poll(safety) {
Poll::Pending => return Poll::Pending,
Poll::Ready(Some(Ok(_))) => continue,
Poll::Ready(Some(Err(e))) => {
return Poll::Ready(Some(Err(e)))
}
Poll::Ready(Some(Err(e))) => return Poll::Ready(Some(Err(e))),
Poll::Ready(None) => true,
}
}
@ -295,10 +283,7 @@ impl InnerMultipart {
}
// read boundary
InnerState::Boundary => {
match InnerMultipart::read_boundary(
&mut *payload,
&self.boundary,
)? {
match InnerMultipart::read_boundary(&mut *payload, &self.boundary)? {
None => return Poll::Pending,
Some(eof) => {
if eof {
@ -380,12 +365,7 @@ impl Field {
ct: mime::Mime,
inner: Rc<RefCell<InnerField>>,
) -> Self {
Field {
ct,
headers,
inner,
safety,
}
Field { ct, headers, inner, safety }
}
/// Get a map of headers
@ -405,9 +385,7 @@ impl Stream for Field {
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
if self.safety.current() {
let mut inner = self.inner.borrow_mut();
if let Some(mut payload) =
inner.payload.as_ref().unwrap().get_mut(&self.safety)
{
if let Some(mut payload) = inner.payload.as_ref().unwrap().get_mut(&self.safety) {
payload.poll_stream(cx)?;
}
inner.poll(&self.safety)
@ -458,12 +436,7 @@ impl InnerField {
None
};
Ok(InnerField {
boundary,
payload: Some(payload),
eof: false,
length: len,
})
Ok(InnerField { boundary, payload: Some(payload), eof: false, length: len })
}
/// Reads body part content chunk of the specified size.
@ -576,8 +549,7 @@ impl InnerField {
return Poll::Ready(None);
}
let result = if let Some(mut payload) = self.payload.as_ref().unwrap().get_mut(s)
{
let result = if let Some(mut payload) = self.payload.as_ref().unwrap().get_mut(s) {
if !self.eof {
let res = if let Some(ref mut len) = self.length {
InnerField::read_len(&mut *payload, len)
@ -597,7 +569,9 @@ impl InnerField {
Ok(None) => Poll::Pending,
Ok(Some(line)) => {
if line.as_ref() != b"\r\n" {
log::warn!("multipart field did not read all the data or it is malformed");
log::warn!(
"multipart field did not read all the data or it is malformed"
);
}
Poll::Ready(None)
}
@ -620,9 +594,7 @@ struct PayloadRef {
impl PayloadRef {
fn new(payload: PayloadBuffer) -> PayloadRef {
PayloadRef {
payload: Rc::new(payload.into()),
}
PayloadRef { payload: Rc::new(payload.into()) }
}
fn get_mut<'a, 'b>(&'a self, s: &'b Safety) -> Option<RefMut<'a, PayloadBuffer>>
@ -639,9 +611,7 @@ impl PayloadRef {
impl Clone for PayloadRef {
fn clone(&self) -> PayloadRef {
PayloadRef {
payload: Rc::clone(&self.payload),
}
PayloadRef { payload: Rc::clone(&self.payload) }
}
}
@ -713,11 +683,7 @@ impl PayloadBuffer {
where
S: Stream<Item = Result<Bytes, PayloadError>> + 'static,
{
PayloadBuffer {
eof: false,
buf: BytesMut::new(),
stream: stream.boxed_local(),
}
PayloadBuffer { eof: false, buf: BytesMut::new(), stream: stream.boxed_local() }
}
fn poll_stream(&mut self, cx: &mut Context) -> Result<(), PayloadError> {
@ -775,9 +741,7 @@ impl PayloadBuffer {
/// Read bytes until new line delimiter or eof
pub fn readline_or_eof(&mut self) -> Result<Option<Bytes>, MultipartError> {
match self.readline() {
Err(MultipartError::Incomplete) if self.eof => {
Ok(Some(self.buf.split().freeze()))
}
Err(MultipartError::Incomplete) if self.eof => Ok(Some(self.buf.split().freeze())),
line => line,
}
}
@ -808,10 +772,7 @@ mod tests {
}
let mut headers = HeaderMap::new();
headers.insert(
header::CONTENT_TYPE,
header::HeaderValue::from_static("test"),
);
headers.insert(header::CONTENT_TYPE, header::HeaderValue::from_static("test"));
match Multipart::boundary(&headers) {
Err(MultipartError::ParseContentType) => (),
@ -819,10 +780,8 @@ mod tests {
}
let mut headers = HeaderMap::new();
headers.insert(
header::CONTENT_TYPE,
header::HeaderValue::from_static("multipart/mixed"),
);
headers
.insert(header::CONTENT_TYPE, header::HeaderValue::from_static("multipart/mixed"));
match Multipart::boundary(&headers) {
Err(MultipartError::Boundary) => (),
_ => unreachable!("should not happen"),
@ -836,10 +795,7 @@ mod tests {
),
);
assert_eq!(
Multipart::boundary(&headers).unwrap(),
"5c02368e880e436dab70ed54e1c58209"
);
assert_eq!(Multipart::boundary(&headers).unwrap(), "5c02368e880e436dab70ed54e1c58209");
}
fn create_stream() -> (
@ -859,21 +815,14 @@ mod tests {
impl SlowStream {
fn new(bytes: Bytes) -> SlowStream {
return SlowStream {
bytes,
pos: 0,
ready: false,
};
return SlowStream { bytes, pos: 0, ready: false };
}
}
impl Stream for SlowStream {
type Item = Result<Bytes, PayloadError>;
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context,
) -> Poll<Option<Self::Item>> {
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
if !this.ready {
this.ready = true;
@ -1112,16 +1061,10 @@ mod tests {
sender.feed_data(Bytes::from("line2"));
lazy(|cx| payload.poll_stream(cx)).await.unwrap();
assert_eq!(
Some(Bytes::from("line")),
payload.read_until(b"ne").unwrap()
);
assert_eq!(Some(Bytes::from("line")), payload.read_until(b"ne").unwrap());
assert_eq!(payload.buf.len(), 6);
assert_eq!(
Some(Bytes::from("1line2")),
payload.read_until(b"2").unwrap()
);
assert_eq!(Some(Bytes::from("1line2")), payload.read_until(b"2").unwrap());
assert_eq!(payload.buf.len(), 0);
}
}

View file

@ -89,8 +89,7 @@ impl<Err> CookieSessionInner<Err> {
state: impl Iterator<Item = (String, String)>,
) -> Result<(), CookieSessionError> {
let state: HashMap<String, String> = state.collect();
let value =
serde_json::to_string(&state).map_err(CookieSessionError::Serialize)?;
let value = serde_json::to_string(&state).map_err(CookieSessionError::Serialize)?;
if value.len() > 4064 {
return Err(CookieSessionError::Overflow);
}
@ -153,9 +152,7 @@ impl<Err> CookieSessionInner<Err> {
let cookie_opt = match self.security {
CookieSecurity::Signed => jar.signed(&self.key).get(&self.name),
CookieSecurity::Private => {
jar.private(&self.key).get(&self.name)
}
CookieSecurity::Private => jar.private(&self.key).get(&self.name),
};
if let Some(cookie) = cookie_opt {
if let Ok(val) = serde_json::from_str(cookie.value()) {
@ -216,20 +213,14 @@ impl<Err> CookieSession<Err> {
///
/// Panics if key length is less than 32 bytes.
pub fn signed(key: &[u8]) -> Self {
CookieSession(Rc::new(CookieSessionInner::new(
key,
CookieSecurity::Signed,
)))
CookieSession(Rc::new(CookieSessionInner::new(key, CookieSecurity::Signed)))
}
/// Construct new *private* `CookieSessionBackend` instance.
///
/// Panics if key length is less than 32 bytes.
pub fn private(key: &[u8]) -> Self {
CookieSession(Rc::new(CookieSessionInner::new(
key,
CookieSecurity::Private,
)))
CookieSession(Rc::new(CookieSessionInner::new(key, CookieSecurity::Private)))
}
/// Sets the `path` field in the session cookie being built.
@ -310,10 +301,7 @@ where
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(CookieSessionMiddleware {
service,
inner: self.0.clone(),
})
ok(CookieSessionMiddleware { service, inner: self.0.clone() })
}
}
@ -400,64 +388,52 @@ mod tests {
#[ntex::test]
async fn cookie_session() {
let app = test::init_service(
App::new()
.wrap(CookieSession::signed(&[0; 32]).secure(false))
.service(web::resource("/").to(|ses: Session| async move {
App::new().wrap(CookieSession::signed(&[0; 32]).secure(false)).service(
web::resource("/").to(|ses: Session| async move {
let _ = ses.set("counter", 100);
"test"
})),
}),
),
)
.await;
let request = test::TestRequest::get().to_request();
let response = app.call(request).await.unwrap();
assert!(response
.response()
.cookies()
.find(|c| c.name() == "ntex-session")
.is_some());
assert!(response.response().cookies().find(|c| c.name() == "ntex-session").is_some());
}
#[ntex::test]
async fn private_cookie() {
let app = test::init_service(
App::new()
.wrap(CookieSession::private(&[0; 32]).secure(false))
.service(web::resource("/").to(|ses: Session| async move {
App::new().wrap(CookieSession::private(&[0; 32]).secure(false)).service(
web::resource("/").to(|ses: Session| async move {
let _ = ses.set("counter", 100);
"test"
})),
}),
),
)
.await;
let request = test::TestRequest::get().to_request();
let response = app.call(request).await.unwrap();
assert!(response
.response()
.cookies()
.find(|c| c.name() == "ntex-session")
.is_some());
assert!(response.response().cookies().find(|c| c.name() == "ntex-session").is_some());
}
#[ntex::test]
async fn cookie_session_extractor() {
let app = test::init_service(
App::new()
.wrap(CookieSession::signed(&[0; 32]).secure(false))
.service(web::resource("/").to(|ses: Session| async move {
App::new().wrap(CookieSession::signed(&[0; 32]).secure(false)).service(
web::resource("/").to(|ses: Session| async move {
let _ = ses.set("counter", 100);
"test"
})),
}),
),
)
.await;
let request = test::TestRequest::get().to_request();
let response = app.call(request).await.unwrap();
assert!(response
.response()
.cookies()
.find(|c| c.name() == "ntex-session")
.is_some());
assert!(response.response().cookies().find(|c| c.name() == "ntex-session").is_some());
}
#[ntex::test]
@ -486,17 +462,11 @@ mod tests {
let request = test::TestRequest::get().to_request();
let response = app.call(request).await.unwrap();
let cookie = response
.response()
.cookies()
.find(|c| c.name() == "ntex-test")
.unwrap()
.clone();
let cookie =
response.response().cookies().find(|c| c.name() == "ntex-test").unwrap().clone();
assert_eq!(cookie.path().unwrap(), "/test/");
let request = test::TestRequest::with_uri("/test/")
.cookie(cookie)
.to_request();
let request = test::TestRequest::with_uri("/test/").cookie(cookie).to_request();
let body = test::read_response(&app, request).await;
assert_eq!(body, Bytes::from_static(b"counter: 100"));
}
@ -510,10 +480,7 @@ mod tests {
let _ = ses.set("counter", 100);
"test"
}))
.service(
web::resource("/test/")
.to(|| async move { "no-changes-in-session" }),
),
.service(web::resource("/test/").to(|| async move { "no-changes-in-session" })),
)
.await;

View file

@ -139,9 +139,7 @@ impl Session {
let mut inner = self.0.borrow_mut();
if inner.status != SessionStatus::Purged {
inner.status = SessionStatus::Changed;
inner
.state
.insert(key.to_owned(), serde_json::to_string(&value)?);
inner.state.insert(key.to_owned(), serde_json::to_string(&value)?);
}
Ok(())
}
@ -190,17 +188,9 @@ impl Session {
pub fn get_changes(
res: &mut WebResponse,
) -> (
SessionStatus,
Option<impl Iterator<Item = (String, String)>>,
) {
if let Some(s_impl) = res
.request()
.extensions()
.get::<Rc<RefCell<SessionInner>>>()
{
let state =
std::mem::replace(&mut s_impl.borrow_mut().state, HashMap::new());
) -> (SessionStatus, Option<impl Iterator<Item = (String, String)>>) {
if let Some(s_impl) = res.request().extensions().get::<Rc<RefCell<SessionInner>>>() {
let state = std::mem::replace(&mut s_impl.borrow_mut().state, HashMap::new());
(s_impl.borrow().status.clone(), Some(state.into_iter()))
} else {
(SessionStatus::Unchanged, None)

View file

@ -1,2 +1,4 @@
max_width = 89
max_width = 96
reorder_imports = true
use_small_heuristics = "max"
use_field_init_shorthand = true