1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-07-10 12:54:20 +02:00

Compare commits

...

15 Commits

59 changed files with 446 additions and 266 deletions

3
.gitignore vendored
View File

@ -13,3 +13,6 @@ guide/build/
# These are backup files generated by rustfmt
**/*.rs.bk
# Configuration directory generated by CLion
.idea

View File

@ -1,6 +1,27 @@
# Changes
## Unreleased - 2020-xx-xx
## 3.0.2 - 2020-09-15
### Fixed
* `NormalizePath` when used with `TrailingSlash::Trim` no longer trims the root path "/". [#1678]
[#1678]: https://github.com/actix/actix-web/pull/1678
## 3.0.1 - 2020-09-13
### Changed
* `middleware::normalize::TrailingSlash` enum is now accessible. [#1673]
[#1673]: https://github.com/actix/actix-web/pull/1673
## 3.0.0 - 2020-09-11
* No significant changes from `3.0.0-beta.4`.
## 3.0.0-beta.4 - 2020-09-09
### Added
* `middleware::NormalizePath` now has configurable behaviour for either always having a trailing
slash, or as the new addition, always trimming trailing slashes. [#1639]

View File

@ -1,8 +1,8 @@
[package]
name = "actix-web"
version = "3.0.0-beta.4"
version = "3.0.2"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix web is a simple, pragmatic and extremely fast web framework for Rust."
description = "Actix web is a powerful, pragmatic, and extremely fast web framework for Rust."
readme = "README.md"
keywords = ["actix", "http", "web", "framework", "async"]
homepage = "https://actix.rs"
@ -76,9 +76,9 @@ actix-macros = "0.1.0"
actix-threadpool = "0.3.1"
actix-tls = "2.0.0"
actix-web-codegen = "0.3.0-beta.1"
actix-http = "2.0.0-beta.4"
awc = { version = "2.0.0-beta.4", default-features = false }
actix-web-codegen = "0.3.0"
actix-http = "2.0.0"
awc = { version = "2.0.0", default-features = false }
bytes = "0.5.3"
derive_more = "0.99.2"
@ -102,7 +102,8 @@ rust-tls = { package = "rustls", version = "0.18.0", optional = true }
tinyvec = { version = "0.3", features = ["alloc"] }
[dev-dependencies]
actix = "0.10.0-alpha.1"
actix = "0.10.0"
actix-http = { version = "2.0.0-beta.4", features = ["actors"] }
rand = "0.7"
env_logger = "0.7"
serde_derive = "1.0"

View File

@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2017-NOW Nikolay Kim
Copyright 2017-NOW Actix Team
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
Copyright (c) 2017 Nikolay Kim
Copyright (c) 2017 Actix Team
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated

View File

@ -1,11 +1,25 @@
## Unreleased
## 3.0.0
* The return type for `ServiceRequest::app_data::<T>()` was changed from returning a `Data<T>` to
simply a `T`. To access a `Data<T>` use `ServiceRequest::app_data::<Data<T>>()`.
* Cookie handling has been offloaded to the `cookie` crate:
* `USERINFO_ENCODE_SET` is no longer exposed. Percent-encoding is still supported; check docs.
* Some types now require lifetime parameters.
* The time crate was updated to `v0.2`, a major breaking change to the time crate, which affects
any `actix-web` method previously expecting a time v0.1 input.
* Setting a cookie's SameSite property, explicitly, to `SameSite::None` will now
result in `SameSite=None` being sent with the response Set-Cookie header.
To create a cookie without a SameSite attribute, remove any calls setting same_site.
* actix-http support for Actors messages was moved to actix-http crate and is enabled
with feature `actors`
* content_length function is removed from actix-http.
You can set Content-Length by normally setting the response body or calling no_chunking function.
@ -40,6 +54,7 @@
* `HttpServer::maxconnrate` is renamed to the more expressive `HttpServer::max_connection_rate`.
## 2.0.0
* `HttpServer::start()` renamed to `HttpServer::run()`. It also possible to

View File

@ -37,17 +37,12 @@
## Documentation
* [Website & User Guide](https://actix.rs)
* [Examples Repository](https://actix.rs/actix-web/actix_web)
* [Examples Repository](https://github.com/actix/examples)
* [API Documentation](https://docs.rs/actix-web)
* [API Documentation (master branch)](https://actix.rs/actix-web/actix_web)
## Example
<h2>
WARNING: This example is for the master branch which is currently in beta stages for v3. For
Actix web v2 see the <a href="https://actix.rs/docs/getting-started/">getting started guide</a>.
</h2>
Dependencies:
```toml

View File

@ -1,11 +0,0 @@
# 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)
**This crate moved to https://github.com/actix/actix-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

View File

@ -1,6 +1,6 @@
[package]
name = "actix-files"
version = "0.3.0-beta.1"
version = "0.3.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Static files support for actix web."
readme = "README.md"
@ -17,9 +17,9 @@ name = "actix_files"
path = "src/lib.rs"
[dependencies]
actix-web = { version = "3.0.0-beta.4", default-features = false }
actix-http = "2.0.0-beta.4"
actix-service = "1.0.1"
actix-web = { version = "3.0.0", default-features = false }
actix-http = "2.0.0"
actix-service = "1.0.6"
bitflags = "1"
bytes = "0.5.3"
futures-core = { version = "0.3.5", default-features = false }
@ -33,4 +33,4 @@ v_htmlescape = "0.10"
[dev-dependencies]
actix-rt = "1.0.0"
actix-web = { version = "3.0.0-beta.4", features = ["openssl"] }
actix-web = { version = "3.0.0", features = ["openssl"] }

View File

@ -1,6 +1,8 @@
#![allow(clippy::borrow_interior_mutable_const, clippy::type_complexity)]
//! Static files support
#![deny(rust_2018_idioms)]
#![allow(clippy::borrow_interior_mutable_const)]
use std::cell::RefCell;
use std::fmt::Write;
use std::fs::{DirEntry, File};
@ -62,6 +64,7 @@ pub struct ChunkedReadFile {
size: u64,
offset: u64,
file: Option<File>,
#[allow(clippy::type_complexity)]
fut:
Option<LocalBoxFuture<'static, Result<(File, Bytes), BlockingError<io::Error>>>>,
counter: u64,
@ -72,7 +75,7 @@ impl Stream for ChunkedReadFile {
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut Context,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
if let Some(ref mut fut) = self.fut {
return match Pin::new(fut).poll(cx) {
@ -224,7 +227,7 @@ fn directory_listing(
))
}
type MimeOverride = dyn Fn(&mime::Name) -> DispositionType;
type MimeOverride = dyn Fn(&mime::Name<'_>) -> DispositionType;
/// Static files handling
///
@ -232,12 +235,10 @@ type MimeOverride = dyn Fn(&mime::Name) -> DispositionType;
///
/// ```rust
/// use actix_web::App;
/// use actix_files as fs;
/// use actix_files::Files;
///
/// fn main() {
/// let app = App::new()
/// .service(fs::Files::new("/static", "."));
/// }
/// .service(Files::new("/static", "."));
/// ```
pub struct Files {
path: String,
@ -330,7 +331,7 @@ impl Files {
/// Specifies mime override callback
pub fn mime_override<F>(mut self, f: F) -> Self
where
F: Fn(&mime::Name) -> DispositionType + 'static,
F: Fn(&mime::Name<'_>) -> DispositionType + 'static,
{
self.mime_override = Some(Rc::new(f));
self
@ -469,6 +470,7 @@ pub struct FilesService {
}
impl FilesService {
#[allow(clippy::type_complexity)]
fn handle_err(
&mut self,
e: io::Error,
@ -490,12 +492,13 @@ impl Service for FilesService {
type Request = ServiceRequest;
type Response = ServiceResponse;
type Error = Error;
#[allow(clippy::type_complexity)]
type Future = Either<
Ready<Result<Self::Response, Self::Error>>,
LocalBoxFuture<'static, Result<Self::Response, Self::Error>>,
>;
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
@ -898,7 +901,7 @@ mod tests {
#[actix_rt::test]
async fn test_mime_override() {
fn all_attachment(_: &mime::Name) -> DispositionType {
fn all_attachment(_: &mime::Name<'_>) -> DispositionType {
DispositionType::Attachment
}

View File

@ -1,3 +0,0 @@
# Framed app for actix web
**This crate has been deprecated and removed.**

View File

@ -3,6 +3,10 @@
## Unreleased - 2020-xx-xx
## 2.0.0 - 2020-09-11
* No significant changes from `2.0.0-beta.4`.
## 2.0.0-beta.4 - 2020-09-09
### Changed
* Update actix-codec and actix-utils dependencies.

View File

@ -1,6 +1,6 @@
[package]
name = "actix-http"
version = "2.0.0-beta.4"
version = "2.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix HTTP primitives"
readme = "README.md"
@ -40,14 +40,14 @@ secure-cookies = ["cookie/secure"]
actors = ["actix"]
[dependencies]
actix-service = "1.0.5"
actix-service = "1.0.6"
actix-codec = "0.3.0"
actix-connect = "2.0.0"
actix-utils = "2.0.0"
actix-rt = "1.0.0"
actix-threadpool = "0.3.1"
actix-tls = { version = "2.0.0", optional = true }
actix = { version = "0.10.0-alpha.1", optional = true }
actix = { version = "0.10.0", optional = true }
base64 = "0.12"
bitflags = "1.2"
@ -88,7 +88,7 @@ flate2 = { version = "1.0.13", optional = true }
[dev-dependencies]
actix-server = "1.0.1"
actix-connect = { version = "2.0.0", features = ["openssl"] }
actix-http-test = { version = "2.0.0-alpha.1", features = ["openssl"] }
actix-http-test = { version = "2.0.0", features = ["openssl"] }
actix-tls = { version = "2.0.0", features = ["openssl"] }
criterion = "0.3"
env_logger = "0.7"

View File

@ -714,7 +714,7 @@ mod tests {
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("!");
body.push('!');
let body = resp_body.downcast_ref::<String>().unwrap();
assert_eq!(body, "hello cast!");
let not_body = resp_body.downcast_ref::<()>();

View File

@ -119,11 +119,11 @@ where
match poll_fn(|cx| Poll::Ready(inner.borrow_mut().acquire(&key, cx))).await {
Acquire::Acquired(io, created) => {
// use existing connection
return Ok(IoConnection::new(
Ok(IoConnection::new(
io,
created,
Some(Acquired(key, Some(inner))),
));
))
}
Acquire::Available => {
// open tcp connection

View File

@ -283,11 +283,11 @@ impl DispositionParam {
/// Some("\u{1f600}.svg".as_bytes()));
/// ```
///
/// # WARN
/// # Security Note
///
/// If "filename" parameter is supplied, do not use the file name blindly, check and possibly
/// change to match local file system conventions if applicable, and do not use directory path
/// information that may be present. See [RFC2183](https://tools.ietf.org/html/rfc2183#section-2.3)
/// .
/// information that may be present. See [RFC2183](https://tools.ietf.org/html/rfc2183#section-2.3).
#[derive(Clone, Debug, PartialEq)]
pub struct ContentDisposition {
/// The disposition type

View File

@ -1,5 +1,6 @@
//! Basic http primitives for actix-net framework.
#![warn(rust_2018_idioms, warnings)]
#![deny(rust_2018_idioms)]
#![allow(
clippy::type_complexity,
clippy::too_many_arguments,

View File

@ -87,7 +87,7 @@ mod tests {
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("!");
body.push('!');
let body = resp_body.downcast_ref::<String>().unwrap();
assert_eq!(body, "hello cast!");
let not_body = resp_body.downcast_ref::<()>();

View File

@ -1,11 +0,0 @@
# Identity service 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-identity)](https://crates.io/crates/actix-identity) [![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.**
## Documentation & community resources
* [User Guide](https://actix.rs/docs/)
* [API Documentation](https://docs.rs/actix-identity/)
* [Chat on gitter](https://gitter.im/actix/actix)
* Cargo package: [actix-session](https://crates.io/crates/actix-identity)
* Minimum supported Rust version: 1.34 or later

View File

@ -3,6 +3,14 @@
## Unreleased - 2020-xx-xx
## 3.0.0 - 2020-09-11
* No significant changes from `3.0.0-beta.2`.
## 3.0.0-beta.2 - 2020-09-10
* Update `actix-*` dependencies to latest versions.
## 0.3.0-beta.1 - 2020-07-15
* Update `actix-web` to 3.0.0-beta.1

View File

@ -1,6 +1,6 @@
[package]
name = "actix-multipart"
version = "0.3.0-beta.1"
version = "0.3.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Multipart support for actix web framework."
readme = "README.md"
@ -16,8 +16,8 @@ name = "actix_multipart"
path = "src/lib.rs"
[dependencies]
actix-web = { version = "3.0.0-beta.4", default-features = false }
actix-service = "1.0.1"
actix-web = { version = "3.0.0", default-features = false }
actix-service = "1.0.6"
actix-utils = "2.0.0"
bytes = "0.5.3"
derive_more = "0.99.2"
@ -29,4 +29,4 @@ twoway = "0.2"
[dev-dependencies]
actix-rt = "1.0.0"
actix-http = "2.0.0-beta.4"
actix-http = "2.0.0"

View File

@ -1,3 +1,6 @@
//! Multipart form support for Actix web.
#![deny(rust_2018_idioms)]
#![allow(clippy::borrow_interior_mutable_const)]
mod error;

View File

@ -1,4 +1,5 @@
//! Multipart payload support
use std::cell::{Cell, RefCell, RefMut};
use std::convert::TryFrom;
use std::marker::PhantomData;
@ -108,7 +109,7 @@ impl Stream for Multipart {
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut Context,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
if let Some(err) = self.error.take() {
Poll::Ready(Some(Err(err)))
@ -244,7 +245,7 @@ impl InnerMultipart {
fn poll(
&mut self,
safety: &Safety,
cx: &mut Context,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Field, MultipartError>>> {
if self.state == InnerState::Eof {
Poll::Ready(None)
@ -416,7 +417,10 @@ impl Field {
impl Stream for Field {
type Item = Result<Bytes, MultipartError>;
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>> {
if self.safety.current() {
let mut inner = self.inner.borrow_mut();
if let Some(mut payload) =
@ -434,7 +438,7 @@ impl Stream for Field {
}
impl fmt::Debug for Field {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "\nField: {}", self.ct)?;
writeln!(f, " boundary: {}", self.inner.borrow().boundary)?;
writeln!(f, " headers:")?;
@ -689,7 +693,7 @@ impl Safety {
self.clean.get()
}
fn clone(&self, cx: &mut Context) -> Safety {
fn clone(&self, cx: &mut Context<'_>) -> Safety {
let payload = Rc::clone(&self.payload);
let s = Safety {
task: LocalWaker::new(),
@ -734,7 +738,7 @@ impl PayloadBuffer {
}
}
fn poll_stream(&mut self, cx: &mut Context) -> Result<(), PayloadError> {
fn poll_stream(&mut self, cx: &mut Context<'_>) -> Result<(), PayloadError> {
loop {
match Pin::new(&mut self.stream).poll_next(cx) {
Poll::Ready(Some(Ok(data))) => self.buf.extend_from_slice(&data),
@ -887,7 +891,7 @@ mod tests {
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context,
cx: &mut Context<'_>,
) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
if !this.ready {

View File

@ -1,11 +0,0 @@
# Session 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-session)](https://crates.io/crates/actix-session) [![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.**
## Documentation & community resources
* [User Guide](https://actix.rs/docs/)
* [API Documentation](https://docs.rs/actix-session/)
* [Chat on gitter](https://gitter.im/actix/actix)
* Cargo package: [actix-session](https://crates.io/crates/actix-session)
* Minimum supported Rust version: 1.34 or later

View File

@ -1,6 +1,14 @@
# Changes
## [Unreleased] - 2020-xx-xx
## Unreleased - 2020-xx-xx
## 3.0.0 - 2020-09-11
* No significant changes from `3.0.0-beta.2`.
## 3.0.0-beta.2 - 2020-09-10
* Update `actix-*` dependencies to latest versions.
## [3.0.0-beta.1] - 2020-xx-xx

View File

@ -1,6 +1,6 @@
[package]
name = "actix-web-actors"
version = "3.0.0-beta.1"
version = "3.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix actors support for actix web framework."
readme = "README.md"
@ -16,9 +16,9 @@ name = "actix_web_actors"
path = "src/lib.rs"
[dependencies]
actix = "0.10.0-alpha.2"
actix-web = { version = "3.0.0-beta.4", default-features = false }
actix-http = "2.0.0-beta.4"
actix = "0.10.0"
actix-web = { version = "3.0.0", default-features = false }
actix-http = "2.0.0"
actix-codec = "0.3.0"
bytes = "0.5.2"
futures-channel = { version = "0.3.5", default-features = false }
@ -26,6 +26,6 @@ futures-core = { version = "0.3.5", default-features = false }
pin-project = "0.4.17"
[dev-dependencies]
actix-rt = "1.0.0"
actix-rt = "1.1.1"
env_logger = "0.7"
futures-util = { version = "0.3.5", default-features = false }

View File

@ -1,5 +1,8 @@
#![allow(clippy::borrow_interior_mutable_const)]
//! Actix actors integration for Actix web framework
#![deny(rust_2018_idioms)]
#![allow(clippy::borrow_interior_mutable_const)]
mod context;
pub mod ws;

View File

@ -1,6 +1,13 @@
# Changes
## Unreleased - 2020-xx-xx
* Added compile success and failure testing. [#1677]
[#1677]: https://github.com/actix/actix-web/pull/1677
## 0.3.0 - 2020-09-11
* No significant changes from `0.3.0-beta.1`.
## 0.3.0-beta.1 - 2020-07-14

View File

@ -1,6 +1,6 @@
[package]
name = "actix-web-codegen"
version = "0.3.0-beta.1"
version = "0.3.0"
description = "Actix web proc macros"
readme = "README.md"
homepage = "https://actix.rs"
@ -20,5 +20,6 @@ proc-macro2 = "1"
[dev-dependencies]
actix-rt = "1.0.0"
actix-web = "3.0.0-beta.4"
actix-web = "3.0.0"
futures-util = { version = "0.3.5", default-features = false }
trybuild = "1"

View File

@ -1,8 +1,22 @@
# Helper and convenience macros for Actix-web. [![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-web-codegen)](https://crates.io/crates/actix-web-codegen) [![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)
# actix-web-codegen
> Helper and convenience macros for Actix Web
[![crates.io](https://meritbadge.herokuapp.com/actix-web-codegen)](https://crates.io/crates/actix-web-codegen)
[![Documentation](https://docs.rs/actix-web-codegen/badge.svg)](https://docs.rs/actix-web)
[![Version](https://img.shields.io/badge/rustc-1.42+-ab6000.svg)](https://blog.rust-lang.org/2020/03/12/Rust-1.42.html)
[![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)
[![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)
## Documentation & Resources
* [API Documentation](https://docs.rs/actix-web-codegen/)
* [Chat on gitter](https://gitter.im/actix/actix)
* Cargo package: [actix-web-codegen](https://crates.io/crates/actix-web-codegen)
* Minimum supported Rust version: 1.40 or later
- [API Documentation](https://docs.rs/actix-web-codegen)
- [Chat on Gitter](https://gitter.im/actix/actix-web)
- Cargo package: [actix-web-codegen](https://crates.io/crates/actix-web-codegen)
- Minimum supported Rust version: 1.42 or later.
## Compile Testing
Uses the [`trybuild`] crate. All compile fail tests should include a stderr file generated by `trybuild`. See the [workflow section](https://github.com/dtolnay/trybuild#workflow) of the trybuild docs for info on how to do this.
[`trybuild`]: https://github.com/dtolnay/trybuild

View File

@ -85,7 +85,7 @@ pub fn put(args: TokenStream, input: TokenStream) -> TokenStream {
///
/// Syntax: `#[delete("path" [, attributes])]`
///
/// Attributes are the same as in [get](attr.get.html)
/// Attributes are the same as in [get](attr.get.html).
#[proc_macro_attribute]
pub fn delete(args: TokenStream, input: TokenStream) -> TokenStream {
route::generate(args, input, route::GuardType::Delete)
@ -95,7 +95,7 @@ pub fn delete(args: TokenStream, input: TokenStream) -> TokenStream {
///
/// Syntax: `#[head("path" [, attributes])]`
///
/// Attributes are the same as in [head](attr.head.html)
/// Attributes are the same as in [get](attr.get.html).
#[proc_macro_attribute]
pub fn head(args: TokenStream, input: TokenStream) -> TokenStream {
route::generate(args, input, route::GuardType::Head)
@ -105,7 +105,7 @@ pub fn head(args: TokenStream, input: TokenStream) -> TokenStream {
///
/// Syntax: `#[connect("path" [, attributes])]`
///
/// Attributes are the same as in [connect](attr.connect.html)
/// Attributes are the same as in [get](attr.get.html).
#[proc_macro_attribute]
pub fn connect(args: TokenStream, input: TokenStream) -> TokenStream {
route::generate(args, input, route::GuardType::Connect)
@ -115,7 +115,7 @@ pub fn connect(args: TokenStream, input: TokenStream) -> TokenStream {
///
/// Syntax: `#[options("path" [, attributes])]`
///
/// Attributes are the same as in [options](attr.options.html)
/// Attributes are the same as in [get](attr.get.html).
#[proc_macro_attribute]
pub fn options(args: TokenStream, input: TokenStream) -> TokenStream {
route::generate(args, input, route::GuardType::Options)
@ -125,7 +125,7 @@ pub fn options(args: TokenStream, input: TokenStream) -> TokenStream {
///
/// Syntax: `#[trace("path" [, attributes])]`
///
/// Attributes are the same as in [trace](attr.trace.html)
/// Attributes are the same as in [get](attr.get.html).
#[proc_macro_attribute]
pub fn trace(args: TokenStream, input: TokenStream) -> TokenStream {
route::generate(args, input, route::GuardType::Trace)
@ -135,7 +135,7 @@ pub fn trace(args: TokenStream, input: TokenStream) -> TokenStream {
///
/// Syntax: `#[patch("path" [, attributes])]`
///
/// Attributes are the same as in [patch](attr.patch.html)
/// Attributes are the same as in [get](attr.get.html).
#[proc_macro_attribute]
pub fn patch(args: TokenStream, input: TokenStream) -> TokenStream {
route::generate(args, input, route::GuardType::Patch)

View File

@ -0,0 +1,7 @@
#[test]
fn compile_macros() {
let t = trybuild::TestCases::new();
t.pass("tests/trybuild/simple.rs");
t.compile_fail("tests/trybuild/simple-fail.rs");
}

View File

@ -0,0 +1,25 @@
use actix_web::*;
#[get("/one", other)]
async fn one() -> impl Responder {
HttpResponse::Ok()
}
#[post(/two)]
async fn two() -> impl Responder {
HttpResponse::Ok()
}
static PATCH_PATH: &str = "/three";
#[patch(PATCH_PATH)]
async fn three() -> impl Responder {
HttpResponse::Ok()
}
#[delete("/four", "/five")]
async fn four() -> impl Responder {
HttpResponse::Ok()
}
fn main() {}

View File

@ -0,0 +1,23 @@
error: Unknown attribute.
--> $DIR/simple-fail.rs:3:15
|
3 | #[get("/one", other)]
| ^^^^^
error: expected identifier or literal
--> $DIR/simple-fail.rs:8:8
|
8 | #[post(/two)]
| ^
error: Unknown attribute.
--> $DIR/simple-fail.rs:15:9
|
15 | #[patch(PATCH_PATH)]
| ^^^^^^^^^^
error: Multiple paths specified! Should be only one!
--> $DIR/simple-fail.rs:20:19
|
20 | #[delete("/four", "/five")]
| ^^^^^^^

View File

@ -0,0 +1,15 @@
use actix_web::*;
#[get("/config")]
async fn config() -> impl Responder {
HttpResponse::Ok()
}
#[actix_web::main]
async fn main() {
let srv = test::start(|| App::new().service(config));
let request = srv.get("/config");
let response = request.send().await.unwrap();
assert!(response.status().is_success());
}

View File

@ -3,6 +3,11 @@
## Unreleased - 2020-xx-xx
## 2.0.0 - 2020-09-11
### Changed
* `Client::build` was renamed to `Client::builder`.
## 2.0.0-beta.4 - 2020-09-09
### Changed
* Update actix-codec & actix-tls dependencies.

View File

@ -1,6 +1,6 @@
[package]
name = "awc"
version = "2.0.0-beta.4"
version = "2.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Async HTTP client library that uses the Actix runtime."
readme = "README.md"
@ -38,8 +38,8 @@ compress = ["actix-http/compress"]
[dependencies]
actix-codec = "0.3.0"
actix-service = "1.0.1"
actix-http = "2.0.0-beta.4"
actix-service = "1.0.6"
actix-http = "2.0.0"
actix-rt = "1.0.0"
base64 = "0.12"
@ -58,9 +58,9 @@ rust-tls = { version = "0.18.0", package = "rustls", optional = true, features =
[dev-dependencies]
actix-connect = { version = "2.0.0", features = ["openssl"] }
actix-web = { version = "3.0.0-beta.4", features = ["openssl"] }
actix-http = { version = "2.0.0-beta.4", features = ["openssl"] }
actix-http-test = { version = "2.0.0-alpha.1", features = ["openssl"] }
actix-web = { version = "3.0.0", features = ["openssl"] }
actix-http = { version = "2.0.0", features = ["openssl"] }
actix-http-test = { version = "2.0.0", features = ["openssl"] }
actix-utils = "2.0.0"
actix-server = "1.0.0"
actix-tls = { version = "2.0.0", features = ["openssl", "rustls"] }

View File

@ -1,4 +1,4 @@
#![warn(rust_2018_idioms, warnings)]
#![deny(rust_2018_idioms)]
#![allow(
clippy::type_complexity,
clippy::borrow_interior_mutable_const,
@ -166,8 +166,9 @@ impl Client {
Client::default()
}
/// Build client instance.
pub fn build() -> ClientBuilder {
/// Create `Client` builder.
/// This function is equivalent of `ClientBuilder::new()`.
pub fn builder() -> ClientBuilder {
ClientBuilder::new()
}

View File

@ -623,7 +623,7 @@ mod tests {
#[actix_rt::test]
async fn test_client_header() {
let req = Client::build()
let req = Client::builder()
.header(header::CONTENT_TYPE, "111")
.finish()
.get("/");
@ -641,7 +641,7 @@ mod tests {
#[actix_rt::test]
async fn test_client_header_override() {
let req = Client::build()
let req = Client::builder()
.header(header::CONTENT_TYPE, "111")
.finish()
.get("/")

View File

@ -193,11 +193,7 @@ impl RequestSender {
}
};
SendClientRequest::new(
fut,
response_decompress,
timeout.or_else(|| config.timeout),
)
SendClientRequest::new(fut, response_decompress, timeout.or(config.timeout))
}
pub(crate) fn send_json<T: Serialize>(

View File

@ -434,7 +434,7 @@ mod tests {
#[actix_rt::test]
async fn test_header_override() {
let req = Client::build()
let req = Client::builder()
.header(header::CONTENT_TYPE, "111")
.finish()
.ws("/")

View File

@ -120,7 +120,7 @@ async fn test_timeout() {
.timeout(Duration::from_secs(15))
.finish();
let client = awc::Client::build()
let client = awc::Client::builder()
.connector(connector)
.timeout(Duration::from_millis(50))
.finish();
@ -141,7 +141,7 @@ async fn test_timeout_override() {
})))
});
let client = awc::Client::build()
let client = awc::Client::builder()
.timeout(Duration::from_millis(50000))
.finish();
let request = client
@ -291,7 +291,7 @@ async fn test_connection_wait_queue() {
})
.await;
let client = awc::Client::build()
let client = awc::Client::builder()
.connector(awc::Connector::new().limit(1).finish())
.finish();
@ -340,7 +340,7 @@ async fn test_connection_wait_queue_force_close() {
})
.await;
let client = awc::Client::build()
let client = awc::Client::builder()
.connector(awc::Connector::new().limit(1).finish())
.finish();

View File

@ -47,7 +47,7 @@ async fn test_connection_window_size() {
.set_alpn_protos(b"\x02h2\x08http/1.1")
.map_err(|e| log::error!("Can not set alpn protocol: {:?}", e));
let client = awc::Client::build()
let client = awc::Client::builder()
.connector(awc::Connector::new().ssl(builder.build()).finish())
.initial_window_size(100)
.initial_connection_window_size(100)

View File

@ -82,7 +82,7 @@ async fn _test_connection_reuse_h2() {
.dangerous()
.set_certificate_verifier(Arc::new(danger::NoCertificateVerification {}));
let client = awc::Client::build()
let client = awc::Client::builder()
.connector(awc::Connector::new().rustls(Arc::new(config)).finish())
.finish();

View File

@ -62,7 +62,7 @@ async fn test_connection_reuse_h2() {
.set_alpn_protos(b"\x02h2\x08http/1.1")
.map_err(|e| log::error!("Can not set alpn protocol: {:?}", e));
let client = awc::Client::build()
let client = awc::Client::builder()
.connector(awc::Connector::new().ssl(builder.build()).finish())
.finish();

View File

@ -1,6 +1,3 @@
#![warn(rust_2018_idioms, warnings)]
#![allow(clippy::needless_doctest_main, clippy::type_complexity)]
//! Actix web is a powerful, pragmatic, and extremely fast web framework for Rust.
//!
//! ## Example
@ -59,7 +56,7 @@
//! * Middlewares ([Logger, Session, CORS, etc](https://actix.rs/docs/middleware/))
//! * Includes an async [HTTP client](https://actix.rs/actix-web/actix_web/client/index.html)
//! * Supports [Actix actor framework](https://github.com/actix/actix)
//! * Runs on stable Rust 1.41+
//! * Runs on stable Rust 1.42+
//!
//! ## Crate Features
//!
@ -68,6 +65,11 @@
//! * `rustls` - HTTPS support via `rustls` crate, supports `HTTP/2`
//! * `secure-cookies` - secure cookies support
#![deny(rust_2018_idioms)]
#![allow(clippy::needless_doctest_main, clippy::type_complexity)]
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
mod app;
mod app_service;
mod config;

View File

@ -9,7 +9,7 @@ mod condition;
mod defaultheaders;
pub mod errhandlers;
mod logger;
mod normalize;
pub mod normalize;
pub use self::condition::Condition;
pub use self::defaultheaders::DefaultHeaders;

View File

@ -79,6 +79,7 @@ where
}
}
#[doc(hidden)]
pub struct NormalizePathNormalization<S> {
service: S,
merge_slash: Regex,
@ -113,6 +114,10 @@ where
// normalize multiple /'s to one /
let path = self.merge_slash.replace_all(&path, "/");
// Ensure root paths are still resolvable. If resulting path is blank after previous step
// it means the path was one or more slashes. Reduce to single slash.
let path = if path.is_empty() { "/" } else { path.as_ref() };
// Check whether the path has been changed
//
// This check was previously implemented as string length comparison
@ -158,10 +163,23 @@ mod tests {
let mut app = init_service(
App::new()
.wrap(NormalizePath::default())
.service(web::resource("/").to(HttpResponse::Ok))
.service(web::resource("/v1/something/").to(HttpResponse::Ok)),
)
.await;
let req = TestRequest::with_uri("/").to_request();
let res = call_service(&mut app, req).await;
assert!(res.status().is_success());
let req = TestRequest::with_uri("/?query=test").to_request();
let res = call_service(&mut app, req).await;
assert!(res.status().is_success());
let req = TestRequest::with_uri("///").to_request();
let res = call_service(&mut app, req).await;
assert!(res.status().is_success());
let req = TestRequest::with_uri("/v1//something////").to_request();
let res = call_service(&mut app, req).await;
assert!(res.status().is_success());
@ -184,10 +202,24 @@ mod tests {
let mut app = init_service(
App::new()
.wrap(NormalizePath(TrailingSlash::Trim))
.service(web::resource("/").to(HttpResponse::Ok))
.service(web::resource("/v1/something").to(HttpResponse::Ok)),
)
.await;
// root paths should still work
let req = TestRequest::with_uri("/").to_request();
let res = call_service(&mut app, req).await;
assert!(res.status().is_success());
let req = TestRequest::with_uri("/?query=test").to_request();
let res = call_service(&mut app, req).await;
assert!(res.status().is_success());
let req = TestRequest::with_uri("///").to_request();
let res = call_service(&mut app, req).await;
assert!(res.status().is_success());
let req = TestRequest::with_uri("/v1/something////").to_request();
let res = call_service(&mut app, req).await;
assert!(res.status().is_success());

View File

@ -368,7 +368,7 @@ mod tests {
}))
.route(web::post().to(|| async {
delay_for(Duration::from_millis(100)).await;
HttpResponse::Created()
Ok::<_, ()>(HttpResponse::Created())
}))
.route(web::delete().to(|| async {
delay_for(Duration::from_millis(100)).await;

View File

@ -826,7 +826,7 @@ mod tests {
async fn test_scope_variable_segment() {
let mut srv =
init_service(App::new().service(web::scope("/ab-{project}").service(
web::resource("/path1").to(|r: HttpRequest| async move {
web::resource("/path1").to(|r: HttpRequest| {
HttpResponse::Ok()
.body(format!("project: {}", &r.match_info()["project"]))
}),
@ -926,7 +926,7 @@ mod tests {
async fn test_nested_scope_with_variable_segment() {
let mut srv = init_service(App::new().service(web::scope("/app").service(
web::scope("/{project_id}").service(web::resource("/path1").to(
|r: HttpRequest| async move {
|r: HttpRequest| {
HttpResponse::Created()
.body(format!("project: {}", &r.match_info()["project_id"]))
},
@ -951,7 +951,7 @@ mod tests {
async fn test_nested2_scope_with_variable_segment() {
let mut srv = init_service(App::new().service(web::scope("/app").service(
web::scope("/{project}").service(web::scope("/{id}").service(
web::resource("/path1").to(|r: HttpRequest| async move {
web::resource("/path1").to(|r: HttpRequest| {
HttpResponse::Created().body(format!(
"project: {} - {}",
&r.match_info()["project"],
@ -1178,7 +1178,7 @@ mod tests {
);
s.route(
"/",
web::get().to(|req: HttpRequest| async move {
web::get().to(|req: HttpRequest| {
HttpResponse::Ok().body(
req.url_for("youtube", &["xxxxxx"]).unwrap().to_string(),
)
@ -1199,7 +1199,7 @@ mod tests {
async fn test_url_for_nested() {
let mut srv = init_service(App::new().service(web::scope("/a").service(
web::scope("/b").service(web::resource("/c/{stuff}").name("c").route(
web::get().to(|req: HttpRequest| async move {
web::get().to(|req: HttpRequest| {
HttpResponse::Ok()
.body(format!("{}", req.url_for("c", &["12345"]).unwrap()))
}),

View File

@ -822,7 +822,7 @@ where
}
};
Client::build().connector(connector).finish()
Client::builder().connector(connector).finish()
};
TestServer {
@ -1072,14 +1072,9 @@ mod tests {
let mut app = init_service(
App::new().service(
web::resource("/index.html")
.route(web::put().to(|| async { HttpResponse::Ok().body("put!") }))
.route(
web::patch().to(|| async { HttpResponse::Ok().body("patch!") }),
)
.route(
web::delete()
.to(|| async { HttpResponse::Ok().body("delete!") }),
),
.route(web::put().to(|| HttpResponse::Ok().body("put!")))
.route(web::patch().to(|| HttpResponse::Ok().body("patch!")))
.route(web::delete().to(|| HttpResponse::Ok().body("delete!"))),
),
)
.await;
@ -1107,10 +1102,12 @@ mod tests {
#[actix_rt::test]
async fn test_response() {
let mut app =
init_service(App::new().service(web::resource("/index.html").route(
web::post().to(|| async { HttpResponse::Ok().body("welcome!") }),
)))
let mut app = init_service(
App::new().service(
web::resource("/index.html")
.route(web::post().to(|| HttpResponse::Ok().body("welcome!"))),
),
)
.await;
let req = TestRequest::post()
@ -1124,10 +1121,12 @@ mod tests {
#[actix_rt::test]
async fn test_send_request() {
let mut app =
init_service(App::new().service(web::resource("/index.html").route(
web::get().to(|| async { HttpResponse::Ok().body("welcome!") }),
)))
let mut app = init_service(
App::new().service(
web::resource("/index.html")
.route(web::get().to(|| HttpResponse::Ok().body("welcome!"))),
),
)
.await;
let resp = TestRequest::get()
@ -1148,7 +1147,7 @@ mod tests {
#[actix_rt::test]
async fn test_response_json() {
let mut app = init_service(App::new().service(web::resource("/people").route(
web::post().to(|person: web::Json<Person>| async {
web::post().to(|person: web::Json<Person>| {
HttpResponse::Ok().json(person.into_inner())
}),
)))
@ -1169,7 +1168,7 @@ mod tests {
#[actix_rt::test]
async fn test_body_json() {
let mut app = init_service(App::new().service(web::resource("/people").route(
web::post().to(|person: web::Json<Person>| async {
web::post().to(|person: web::Json<Person>| {
HttpResponse::Ok().json(person.into_inner())
}),
)))
@ -1191,7 +1190,7 @@ mod tests {
#[actix_rt::test]
async fn test_request_response_form() {
let mut app = init_service(App::new().service(web::resource("/people").route(
web::post().to(|person: web::Form<Person>| async {
web::post().to(|person: web::Form<Person>| {
HttpResponse::Ok().json(person.into_inner())
}),
)))
@ -1217,7 +1216,7 @@ mod tests {
#[actix_rt::test]
async fn test_request_response_json() {
let mut app = init_service(App::new().service(web::resource("/people").route(
web::post().to(|person: web::Json<Person>| async {
web::post().to(|person: web::Json<Person>| {
HttpResponse::Ok().json(person.into_inner())
}),
)))
@ -1282,53 +1281,54 @@ mod tests {
assert!(res.status().is_success());
}
/*
Comment out until actix decoupled of actix-http:
https://github.com/actix/actix/issues/321
use futures::FutureExt;
#[actix_rt::test]
async fn test_actor() {
use actix::Actor;
use crate::Error;
use actix::prelude::*;
struct MyActor;
impl Actor for MyActor {
type Context = Context<Self>;
}
struct Num(usize);
impl actix::Message for Num {
impl Message for Num {
type Result = usize;
}
impl actix::Actor for MyActor {
type Context = actix::Context<Self>;
}
impl actix::Handler<Num> for MyActor {
impl Handler<Num> for MyActor {
type Result = usize;
fn handle(&mut self, msg: Num, _: &mut Self::Context) -> Self::Result {
msg.0
}
}
let addr = MyActor.start();
async fn actor_handler(
addr: Data<Addr<MyActor>>,
) -> Result<impl Responder, Error> {
// `?` operator tests "actors" feature flag on actix-http
let res = addr.send(Num(1)).await?;
let mut app = init_service(App::new().service(web::resource("/index.html").to(
move || {
addr.send(Num(1)).map(|res| match res {
Ok(res) => {
if res == 1 {
Ok(HttpResponse::Ok())
} else {
Ok(HttpResponse::BadRequest())
}
}
Err(err) => Err(err),
})
},
)))
.await;
let req = TestRequest::post().uri("/index.html").to_request();
let srv = App::new()
.data(addr.clone())
.service(web::resource("/").to(actor_handler));
let mut app = init_service(srv).await;
let req = TestRequest::post().uri("/").to_request();
let res = app.call(req).await.unwrap();
assert!(res.status().is_success());
}
*/
}

View File

@ -195,7 +195,7 @@ impl<T: Serialize> Responder for Form<T> {
/// web::resource("/index.html")
/// // change `Form` extractor configuration
/// .app_data(
/// web::Form::<FormData>::configure(|cfg| cfg.limit(4097))
/// web::FormConfig::default().limit(4097)
/// )
/// .route(web::get().to(index))
/// );

View File

@ -209,10 +209,10 @@ where
/// Json extractor configuration
///
/// # Examples
/// # Example
///
/// ```rust
/// use actix_web::{error, web, App, FromRequest, HttpRequest, HttpResponse};
/// use actix_web::{error, web, App, FromRequest, HttpResponse};
/// use serde_derive::Deserialize;
///
/// #[derive(Deserialize)]
@ -225,35 +225,26 @@ where
/// format!("Welcome {}!", info.username)
/// }
///
/// /// Return either a 400 or 415, and include the error message from serde
/// /// in the response body
/// fn json_error_handler(err: error::JsonPayloadError, _req: &HttpRequest) -> error::Error {
/// let detail = err.to_string();
/// let response = match &err {
/// error::JsonPayloadError::ContentType => {
/// HttpResponse::UnsupportedMediaType().content_type("text/plain").body(detail)
/// }
/// _ => HttpResponse::BadRequest().content_type("text/plain").body(detail),
/// };
/// error::InternalError::from_response(err, response).into()
/// }
///
/// fn main() {
/// let app = App::new().service(
/// web::resource("/index.html")
/// .app_data(
/// // change json extractor configuration
/// web::Json::<Info>::configure(|cfg| {
/// cfg.limit(4096)
/// // Json extractor configuration for this resource.
/// web::JsonConfig::default()
/// .limit(4096) // Limit request payload size
/// .content_type(|mime| { // <- accept text/plain content type
/// mime.type_() == mime::TEXT && mime.subtype() == mime::PLAIN
/// })
/// .error_handler(json_error_handler) // Use our custom error response
/// }))
/// .error_handler(|err, req| { // <- create custom error response
/// error::InternalError::from_response(
/// err, HttpResponse::Conflict().finish()).into()
/// })
/// )
/// .route(web::post().to(index))
/// );
/// }
/// ```
///
#[derive(Clone)]
pub struct JsonConfig {
limit: usize,

View File

@ -188,12 +188,12 @@ where
/// let app = App::new().service(
/// web::resource("/index.html").app_data(
/// // change query extractor configuration
/// web::Query::<Info>::configure(|cfg| {
/// cfg.error_handler(|err, req| { // <- create custom error response
/// web::QueryConfig::default()
/// .error_handler(|err, req| { // <- create custom error response
/// error::InternalError::from_response(
/// err, HttpResponse::Conflict().finish()).into()
/// })
/// }))
/// )
/// .route(web::post().to(index))
/// );
/// }

View File

@ -1,10 +1,15 @@
# Changes
## Unreleased - 2020-xx-xx
* add ability to set address for `TestServer` [#1645]
[#1645]: https://github.com/actix/actix-web/pull/1645
## 2.0.0 - 2020-09-11
* Update actix-codec and actix-utils dependencies.
## [2.0.0-alpha.1] - 2020-05-23
## 2.0.0-alpha.1 - 2020-05-23
* Update the `time` dependency to 0.2.7
* Update `actix-connect` dependency to 2.0.0-alpha.2
* Make `test_server` `async` fn.

View File

@ -1,6 +1,6 @@
[package]
name = "actix-http-test"
version = "2.0.0-alpha.1"
version = "2.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix HTTP test server"
readme = "README.md"
@ -29,14 +29,14 @@ default = []
openssl = ["open-ssl", "awc/openssl"]
[dependencies]
actix-service = "1.0.1"
actix-service = "1.0.6"
actix-codec = "0.3.0"
actix-connect = "2.0.0"
actix-utils = "2.0.0"
actix-rt = "1.0.0"
actix-rt = "1.1.1"
actix-server = "1.0.0"
actix-testing = "1.0.0"
awc = "2.0.0-beta.4"
awc = "2.0.0"
base64 = "0.12"
bytes = "0.5.3"
@ -52,5 +52,5 @@ time = { version = "0.2.7", default-features = false, features = ["std"] }
open-ssl = { version = "0.10", package = "openssl", optional = true }
[dev-dependencies]
actix-web = "3.0.0-beta.4"
actix-http = "2.0.0-beta.4"
actix-web = "3.0.0"
actix-http = "2.0.0"

View File

@ -44,12 +44,20 @@ pub use actix_testing::*;
/// }
/// ```
pub async fn test_server<F: ServiceFactory<TcpStream>>(factory: F) -> TestServer {
let tcp = net::TcpListener::bind("127.0.0.1:0").unwrap();
test_server_with_addr(tcp, factory).await
}
/// Start [`test server`](./fn.test_server.html) on a concrete Address
pub async fn test_server_with_addr<F: ServiceFactory<TcpStream>>(
tcp: net::TcpListener,
factory: F,
) -> TestServer {
let (tx, rx) = mpsc::channel();
// run server in separate thread
thread::spawn(move || {
let sys = System::new("actix-test-server");
let tcp = net::TcpListener::bind("127.0.0.1:0").unwrap();
let local_addr = tcp.local_addr().unwrap();
Server::build()
@ -90,7 +98,7 @@ pub async fn test_server<F: ServiceFactory<TcpStream>>(factory: F) -> TestServer
}
};
Client::build().connector(connector).finish()
Client::builder().connector(connector).finish()
};
actix_connect::start_default_resolver().await.unwrap();

View File

@ -43,7 +43,7 @@ async fn test_start() {
{
use actix_http::client;
let client = awc::Client::build()
let client = awc::Client::builder()
.connector(
client::Connector::new()
.timeout(Duration::from_millis(100))
@ -115,7 +115,7 @@ async fn test_start_ssl() {
.set_alpn_protos(b"\x02h2\x08http/1.1")
.map_err(|e| log::error!("Can not set alpn protocol: {:?}", e));
let client = awc::Client::build()
let client = awc::Client::builder()
.connector(
awc::Connector::new()
.ssl(builder.build())

View File

@ -16,7 +16,8 @@ use futures_util::ready;
use rand::{distributions::Alphanumeric, Rng};
use actix_web::dev::BodyEncoding;
use actix_web::middleware::Compress;
use actix_web::middleware::normalize::TrailingSlash;
use actix_web::middleware::{Compress, NormalizePath};
use actix_web::{dev, test, web, App, Error, HttpResponse};
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
@ -866,6 +867,20 @@ async fn test_slow_request() {
assert!(data.starts_with("HTTP/1.1 408 Request Timeout"));
}
#[actix_rt::test]
async fn test_normalize() {
let srv = test::start_with(test::config().h1(), || {
App::new()
.wrap(NormalizePath::new(TrailingSlash::Trim))
.service(
web::resource("/one").route(web::to(|| HttpResponse::Ok().finish())),
)
});
let response = srv.get("/one/").send().await.unwrap();
assert!(response.status().is_success());
}
// #[cfg(feature = "openssl")]
// #[actix_rt::test]
// async fn test_ssl_handshake_timeout() {