mirror of
https://github.com/fafhrd91/actix-net
synced 2025-08-13 23:38:23 +02:00
Compare commits
25 Commits
connect-v2
...
macros-v0.
Author | SHA1 | Date | |
---|---|---|---|
|
ab496a71b5 | ||
|
76d956e25c | ||
|
89e56cf661 | ||
|
8aca8d4d07 | ||
|
e0dd2a3d76 | ||
|
59e976aaca | ||
|
4cc1c87724 | ||
|
ca39917d2c | ||
|
704af672b9 | ||
|
242bef269f | ||
|
6c65e2a79f | ||
|
e5ca271764 | ||
|
98a2197a09 | ||
|
fb0aa02b3c | ||
|
681eeb497d | ||
|
3e04b87311 | ||
|
77b7826658 | ||
|
b7a9cb7bb4 | ||
|
88d99ac89c | ||
|
7632f51509 | ||
|
d28687d0d7 | ||
|
27c6be9881 | ||
|
119dc39f5b | ||
|
b3010c13e0 | ||
|
fecdfcd8d4 |
2
.github/workflows/clippy-fmt.yml
vendored
2
.github/workflows/clippy-fmt.yml
vendored
@@ -31,4 +31,4 @@ jobs:
|
||||
uses: actions-rs/clippy-check@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --all-features --all --tests
|
||||
args: --workspace --tests
|
||||
|
6
.github/workflows/linux.yml
vendored
6
.github/workflows/linux.yml
vendored
@@ -53,20 +53,20 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --all --bins --examples --tests
|
||||
args: --workspace --bins --examples --tests
|
||||
|
||||
- name: tests
|
||||
uses: actions-rs/cargo@v1
|
||||
timeout-minutes: 40
|
||||
with:
|
||||
command: test
|
||||
args: --all --all-features --no-fail-fast -- --nocapture
|
||||
args: --workspace --exclude=actix-tls --no-fail-fast -- --nocapture
|
||||
|
||||
- name: Generate coverage file
|
||||
if: matrix.version == 'stable' && (github.ref == 'refs/heads/master' || github.event_name == 'pull_request')
|
||||
run: |
|
||||
cargo install cargo-tarpaulin
|
||||
cargo tarpaulin --out Xml --workspace --all-features
|
||||
cargo tarpaulin --out Xml --workspace
|
||||
|
||||
- name: Upload to Codecov
|
||||
if: matrix.version == 'stable' && (github.ref == 'refs/heads/master' || github.event_name == 'pull_request')
|
||||
|
4
.github/workflows/macos.yml
vendored
4
.github/workflows/macos.yml
vendored
@@ -34,10 +34,10 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --all --bins --examples --tests
|
||||
args: --workspace --bins --examples --tests
|
||||
|
||||
- name: tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all --all-features --no-fail-fast -- --nocapture
|
||||
args: --workspace --exclude=actix-tls --no-fail-fast -- --nocapture
|
||||
|
2
.github/workflows/windows-mingw.yml
vendored
2
.github/workflows/windows-mingw.yml
vendored
@@ -42,4 +42,4 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --all --bins --examples --tests
|
||||
args: --workspace --bins --examples --tests
|
||||
|
4
.github/workflows/windows.yml
vendored
4
.github/workflows/windows.yml
vendored
@@ -60,10 +60,10 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --all --bins --examples --tests
|
||||
args: --workspace --bins --examples --tests
|
||||
|
||||
- name: tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all --all-features --no-fail-fast -- --nocapture
|
||||
args: --workspace --exclude=actix-tls --no-fail-fast -- --nocapture
|
||||
|
@@ -34,10 +34,13 @@ This Code of Conduct applies both within project spaces and in public spaces whe
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at fafhrd91@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at robjtede@icloud.com ([@robjtede]) or huyuumi@neet.club ([@JohnTitor]). The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
[@robjtede]: https://github.com/robjtede
|
||||
[@JohnTitor]: https://github.com/JohnTitor
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
@@ -1,10 +1,22 @@
|
||||
# Changes
|
||||
|
||||
## Unreleased - 2020-xx-xx
|
||||
* Upgrade `pin-project` to `1.0`.
|
||||
|
||||
## 0.3.0 - 2020-08-23
|
||||
* No changes from beta 2.
|
||||
|
||||
## 0.3.0-beta.2 - 2020-08-19
|
||||
* Remove unused type parameter from `Framed::replace_codec`.
|
||||
|
||||
## 0.3.0-beta.1 - 2020-08-19
|
||||
* Use `.advance()` instead of `.split_to()`.
|
||||
* Upgrade `tokio-util` to `0.3`.
|
||||
* Improve `BytesCodec` `.encode()` performance
|
||||
* Simplify `BytesCodec` `.decode()`
|
||||
* Rename methods on `Framed` to better describe their use.
|
||||
* Add method on `Framed` to get a pinned reference to the underlying I/O.
|
||||
* Add method on `Framed` check emptiness of read buffer.
|
||||
|
||||
## [0.2.0] - 2019-12-10
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
[package]
|
||||
name = "actix-codec"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
description = "Utilities for encoding and decoding frames"
|
||||
description = "Codec utilities for working with framed protocols."
|
||||
keywords = ["network", "framework", "async", "futures"]
|
||||
homepage = "https://actix.rs"
|
||||
repository = "https://github.com/actix/actix-net.git"
|
||||
@@ -10,7 +10,6 @@ documentation = "https://docs.rs/actix-codec/"
|
||||
categories = ["network-programming", "asynchronous"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2018"
|
||||
workspace = ".."
|
||||
|
||||
[lib]
|
||||
name = "actix_codec"
|
||||
@@ -21,7 +20,7 @@ bitflags = "1.2.1"
|
||||
bytes = "0.5.2"
|
||||
futures-core = { version = "0.3.4", default-features = false }
|
||||
futures-sink = { version = "0.3.4", default-features = false }
|
||||
log = "0.4"
|
||||
pin-project = "1.0.0"
|
||||
tokio = { version = "0.2.5", default-features = false }
|
||||
tokio-util = { version = "0.3.1", default-features = false, features = ["codec"] }
|
||||
log = "0.4"
|
||||
pin-project = "0.4.17"
|
||||
|
@@ -23,6 +23,12 @@ bitflags::bitflags! {
|
||||
|
||||
/// A unified `Stream` and `Sink` interface to an underlying I/O object, using
|
||||
/// the `Encoder` and `Decoder` traits to encode and decode frames.
|
||||
///
|
||||
/// Raw I/O objects work with byte sequences, but higher-level code usually
|
||||
/// wants to batch these into meaningful chunks, called "frames". This
|
||||
/// method layers framing on top of an I/O object, by using the `Encoder`/`Decoder`
|
||||
/// traits to handle encoding and decoding of message frames. Note that
|
||||
/// the incoming and outgoing frame types may be distinct.
|
||||
#[pin_project]
|
||||
pub struct Framed<T, U> {
|
||||
#[pin]
|
||||
@@ -38,15 +44,6 @@ where
|
||||
T: AsyncRead + AsyncWrite,
|
||||
U: Decoder,
|
||||
{
|
||||
/// Provides a `Stream` and `Sink` interface for reading and writing to this
|
||||
/// `Io` object, using `Decode` and `Encode` to read and write the raw data.
|
||||
///
|
||||
/// Raw I/O objects work with byte sequences, but higher-level code usually
|
||||
/// wants to batch these into meaningful chunks, called "frames". This
|
||||
/// method layers framing on top of an I/O object, by using the `Codec`
|
||||
/// traits to handle encoding and decoding of messages frames. Note that
|
||||
/// the incoming and outgoing frame types may be distinct.
|
||||
///
|
||||
/// This function returns a *single* object that is both `Stream` and
|
||||
/// `Sink`; grouping this into a single object is often useful for layering
|
||||
/// things like gzip or TLS, which require both read and write access to the
|
||||
@@ -63,40 +60,13 @@ where
|
||||
}
|
||||
|
||||
impl<T, U> Framed<T, U> {
|
||||
/// Provides a `Stream` and `Sink` interface for reading and writing to this
|
||||
/// `Io` object, using `Decode` and `Encode` to read and write the raw data.
|
||||
///
|
||||
/// Raw I/O objects work with byte sequences, but higher-level code usually
|
||||
/// wants to batch these into meaningful chunks, called "frames". This
|
||||
/// method layers framing on top of an I/O object, by using the `Codec`
|
||||
/// traits to handle encoding and decoding of messages frames. Note that
|
||||
/// the incoming and outgoing frame types may be distinct.
|
||||
///
|
||||
/// This function returns a *single* object that is both `Stream` and
|
||||
/// `Sink`; grouping this into a single object is often useful for layering
|
||||
/// things like gzip or TLS, which require both read and write access to the
|
||||
/// underlying object.
|
||||
///
|
||||
/// This objects takes a stream and a readbuffer and a writebuffer. These
|
||||
/// field can be obtained from an existing `Framed` with the
|
||||
/// `into_parts` method.
|
||||
pub fn from_parts(parts: FramedParts<T, U>) -> Framed<T, U> {
|
||||
Framed {
|
||||
io: parts.io,
|
||||
codec: parts.codec,
|
||||
flags: parts.flags,
|
||||
write_buf: parts.write_buf,
|
||||
read_buf: parts.read_buf,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the underlying codec.
|
||||
pub fn get_codec(&self) -> &U {
|
||||
pub fn codec_ref(&self) -> &U {
|
||||
&self.codec
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the underlying codec.
|
||||
pub fn get_codec_mut(&mut self) -> &mut U {
|
||||
pub fn codec_mut(&mut self) -> &mut U {
|
||||
&mut self.codec
|
||||
}
|
||||
|
||||
@@ -106,20 +76,29 @@ impl<T, U> Framed<T, U> {
|
||||
/// Note that care should be taken to not tamper with the underlying stream
|
||||
/// of data coming in as it may corrupt the stream of frames otherwise
|
||||
/// being worked with.
|
||||
pub fn get_ref(&self) -> &T {
|
||||
pub fn io_ref(&self) -> &T {
|
||||
&self.io
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the underlying I/O stream wrapped by
|
||||
/// `Frame`.
|
||||
/// Returns a mutable reference to the underlying I/O stream.
|
||||
///
|
||||
/// Note that care should be taken to not tamper with the underlying stream
|
||||
/// of data coming in as it may corrupt the stream of frames otherwise
|
||||
/// being worked with.
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
pub fn io_mut(&mut self) -> &mut T {
|
||||
&mut self.io
|
||||
}
|
||||
|
||||
/// Returns a `Pin` of a mutable reference to the underlying I/O stream.
|
||||
pub fn io_pin(self: Pin<&mut Self>) -> Pin<&mut T> {
|
||||
self.project().io
|
||||
}
|
||||
|
||||
/// Check if read buffer is empty.
|
||||
pub fn is_read_buf_empty(&self) -> bool {
|
||||
self.read_buf.is_empty()
|
||||
}
|
||||
|
||||
/// Check if write buffer is empty.
|
||||
pub fn is_write_buf_empty(&self) -> bool {
|
||||
self.write_buf.is_empty()
|
||||
@@ -130,8 +109,15 @@ impl<T, U> Framed<T, U> {
|
||||
self.write_buf.len() >= HW
|
||||
}
|
||||
|
||||
/// Check if framed is able to write more data.
|
||||
///
|
||||
/// `Framed` object considers ready if there is free space in write buffer.
|
||||
pub fn is_write_ready(&self) -> bool {
|
||||
self.write_buf.len() < HW
|
||||
}
|
||||
|
||||
/// Consume the `Frame`, returning `Frame` with different codec.
|
||||
pub fn into_framed<U2, I2>(self, codec: U2) -> Framed<T, U2> {
|
||||
pub fn replace_codec<U2>(self, codec: U2) -> Framed<T, U2> {
|
||||
Framed {
|
||||
codec,
|
||||
io: self.io,
|
||||
@@ -142,7 +128,7 @@ impl<T, U> Framed<T, U> {
|
||||
}
|
||||
|
||||
/// Consume the `Frame`, returning `Frame` with different io.
|
||||
pub fn map_io<F, T2, I2>(self, f: F) -> Framed<T2, U>
|
||||
pub fn into_map_io<F, T2>(self, f: F) -> Framed<T2, U>
|
||||
where
|
||||
F: Fn(T) -> T2,
|
||||
{
|
||||
@@ -156,7 +142,7 @@ impl<T, U> Framed<T, U> {
|
||||
}
|
||||
|
||||
/// Consume the `Frame`, returning `Frame` with different codec.
|
||||
pub fn map_codec<F, U2, I2>(self, f: F) -> Framed<T, U2>
|
||||
pub fn into_map_codec<F, U2>(self, f: F) -> Framed<T, U2>
|
||||
where
|
||||
F: Fn(U) -> U2,
|
||||
{
|
||||
@@ -168,22 +154,6 @@ impl<T, U> Framed<T, U> {
|
||||
write_buf: self.write_buf,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes the `Frame`, returning its underlying I/O stream, the buffer
|
||||
/// with unprocessed data, and the codec.
|
||||
///
|
||||
/// Note that care should be taken to not tamper with the underlying stream
|
||||
/// of data coming in as it may corrupt the stream of frames otherwise
|
||||
/// being worked with.
|
||||
pub fn into_parts(self) -> FramedParts<T, U> {
|
||||
FramedParts {
|
||||
io: self.io,
|
||||
codec: self.codec,
|
||||
flags: self.flags,
|
||||
read_buf: self.read_buf,
|
||||
write_buf: self.write_buf,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Framed<T, U> {
|
||||
@@ -203,13 +173,6 @@ impl<T, U> Framed<T, U> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check if framed is able to write more data.
|
||||
///
|
||||
/// `Framed` object considers ready if there is free space in write buffer.
|
||||
pub fn is_write_ready(&self) -> bool {
|
||||
self.write_buf.len() < HW
|
||||
}
|
||||
|
||||
/// Try to read underlying I/O stream and decode item.
|
||||
pub fn next_item(
|
||||
mut self: Pin<&mut Self>,
|
||||
@@ -376,6 +339,41 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Framed<T, U> {
|
||||
/// This function returns a *single* object that is both `Stream` and
|
||||
/// `Sink`; grouping this into a single object is often useful for layering
|
||||
/// things like gzip or TLS, which require both read and write access to the
|
||||
/// underlying object.
|
||||
///
|
||||
/// These objects take a stream, a read buffer and a write buffer. These
|
||||
/// fields can be obtained from an existing `Framed` with the `into_parts` method.
|
||||
pub fn from_parts(parts: FramedParts<T, U>) -> Framed<T, U> {
|
||||
Framed {
|
||||
io: parts.io,
|
||||
codec: parts.codec,
|
||||
flags: parts.flags,
|
||||
write_buf: parts.write_buf,
|
||||
read_buf: parts.read_buf,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes the `Frame`, returning its underlying I/O stream, the buffer
|
||||
/// with unprocessed data, and the codec.
|
||||
///
|
||||
/// Note that care should be taken to not tamper with the underlying stream
|
||||
/// of data coming in as it may corrupt the stream of frames otherwise
|
||||
/// being worked with.
|
||||
pub fn into_parts(self) -> FramedParts<T, U> {
|
||||
FramedParts {
|
||||
io: self.io,
|
||||
codec: self.codec,
|
||||
flags: self.flags,
|
||||
read_buf: self.read_buf,
|
||||
write_buf: self.write_buf,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `FramedParts` contains an export of the data of a Framed transport.
|
||||
/// It can be used to construct a new `Framed` with a different codec.
|
||||
/// It contains all current buffers and the inner transport.
|
||||
|
@@ -8,7 +8,9 @@
|
||||
//! [`AsyncWrite`]: AsyncWrite
|
||||
//! [`Sink`]: futures_sink::Sink
|
||||
//! [`Stream`]: futures_core::Stream
|
||||
|
||||
#![deny(rust_2018_idioms)]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
mod bcodec;
|
||||
mod framed;
|
||||
|
@@ -1,8 +1,11 @@
|
||||
# Changes
|
||||
|
||||
## Unreleased
|
||||
## Unreleased - 2020-xx-xx
|
||||
|
||||
|
||||
## 2.0.0 - 2020-09-02
|
||||
- No significant changes from `2.0.0-alpha.4`.
|
||||
|
||||
## 2.0.0-alpha.4 - 2020-08-17
|
||||
|
||||
### Changed
|
||||
|
@@ -1,8 +1,8 @@
|
||||
[package]
|
||||
name = "actix-connect"
|
||||
version = "2.0.0-alpha.4"
|
||||
version = "2.0.0"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
description = "Actix connect - tcp connector service"
|
||||
description = "TCP connector service for Actix ecosystem."
|
||||
keywords = ["network", "framework", "async", "futures"]
|
||||
homepage = "https://actix.rs"
|
||||
repository = "https://github.com/actix/actix-net.git"
|
||||
@@ -31,10 +31,11 @@ rustls = ["rust-tls", "tokio-rustls", "webpki"]
|
||||
uri = ["http"]
|
||||
|
||||
[dependencies]
|
||||
actix-service = "1.0.3"
|
||||
actix-codec = "0.2.0"
|
||||
actix-utils = "1.0.6"
|
||||
actix-rt = "1.0.0"
|
||||
actix-service = "1.0.6"
|
||||
actix-codec = "0.3.0"
|
||||
actix-utils = "2.0.0"
|
||||
actix-rt = "1.1.1"
|
||||
|
||||
derive_more = "0.99.2"
|
||||
either = "1.5.3"
|
||||
futures-util = { version = "0.3.4", default-features = false }
|
||||
@@ -44,14 +45,14 @@ trust-dns-proto = { version = "0.19", default-features = false, features = ["tok
|
||||
trust-dns-resolver = { version = "0.19", default-features = false, features = ["tokio-runtime", "system-config"] }
|
||||
|
||||
# openssl
|
||||
open-ssl = { version="0.10", package = "openssl", optional = true }
|
||||
open-ssl = { package = "openssl", version = "0.10", optional = true }
|
||||
tokio-openssl = { version = "0.4.0", optional = true }
|
||||
|
||||
# rustls
|
||||
rust-tls = { version = "0.18.0", package = "rustls", optional = true }
|
||||
rust-tls = { package = "rustls", version = "0.18.0", optional = true }
|
||||
tokio-rustls = { version = "0.14.0", optional = true }
|
||||
webpki = { version = "0.21", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
bytes = "0.5.3"
|
||||
actix-testing = { version="1.0.0" }
|
||||
actix-testing = "1.0.0"
|
||||
|
@@ -43,7 +43,7 @@ pub struct Connect<T> {
|
||||
}
|
||||
|
||||
impl<T: Address> Connect<T> {
|
||||
/// Create `Connect` instance by spliting the string by ':' and convert the second part to u16
|
||||
/// Create `Connect` instance by splitting the string by ':' and convert the second part to u16
|
||||
pub fn new(req: T) -> Connect<T> {
|
||||
let (_, port) = parse(req.host());
|
||||
Connect {
|
||||
@@ -53,7 +53,8 @@ impl<T: Address> Connect<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create new `Connect` instance from host and address. Connector skips name resolution stage for such connect messages.
|
||||
/// Create new `Connect` instance from host and address. Connector skips name resolution stage
|
||||
/// for such connect messages.
|
||||
pub fn with(req: T, addr: SocketAddr) -> Connect<T> {
|
||||
Connect {
|
||||
req,
|
||||
@@ -102,7 +103,7 @@ impl<T: Address> Connect<T> {
|
||||
self.req.port().unwrap_or(self.port)
|
||||
}
|
||||
|
||||
/// Preresolved addresses of the request.
|
||||
/// Pre-resolved addresses of the request.
|
||||
pub fn addrs(&self) -> ConnectAddrsIter<'_> {
|
||||
let inner = match self.addr {
|
||||
None => Either::Left(None),
|
||||
@@ -113,7 +114,7 @@ impl<T: Address> Connect<T> {
|
||||
ConnectAddrsIter { inner }
|
||||
}
|
||||
|
||||
/// Takes preresolved addresses of the request.
|
||||
/// Takes pre-resolved addresses of the request.
|
||||
pub fn take_addrs(&mut self) -> ConnectTakeAddrsIter {
|
||||
let inner = match self.addr.take() {
|
||||
None => Either::Left(None),
|
||||
|
@@ -13,7 +13,7 @@ use futures_util::future::{err, ok, BoxFuture, Either, FutureExt, Ready};
|
||||
use super::connect::{Address, Connect, Connection};
|
||||
use super::error::ConnectError;
|
||||
|
||||
/// Tcp connector service factory
|
||||
/// TCP connector service factory
|
||||
#[derive(Debug)]
|
||||
pub struct TcpConnectorFactory<T>(PhantomData<T>);
|
||||
|
||||
@@ -22,7 +22,7 @@ impl<T> TcpConnectorFactory<T> {
|
||||
TcpConnectorFactory(PhantomData)
|
||||
}
|
||||
|
||||
/// Create tcp connector service
|
||||
/// Create TCP connector service
|
||||
pub fn service(&self) -> TcpConnector<T> {
|
||||
TcpConnector(PhantomData)
|
||||
}
|
||||
@@ -54,7 +54,7 @@ impl<T: Address> ServiceFactory for TcpConnectorFactory<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Tcp connector service
|
||||
/// TCP connector service
|
||||
#[derive(Default, Debug)]
|
||||
pub struct TcpConnector<T>(PhantomData<T>);
|
||||
|
||||
@@ -74,6 +74,7 @@ impl<T: Address> Service for TcpConnector<T> {
|
||||
type Request = Connect<T>;
|
||||
type Response = Connection<T, TcpStream>;
|
||||
type Error = ConnectError;
|
||||
#[allow(clippy::type_complexity)]
|
||||
type Future = Either<TcpConnectorResponse<T>, Ready<Result<Self::Response, Self::Error>>>;
|
||||
|
||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
@@ -94,7 +95,7 @@ impl<T: Address> Service for TcpConnector<T> {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// Tcp stream connector response future
|
||||
/// TCP stream connector response future
|
||||
pub struct TcpConnectorResponse<T> {
|
||||
req: Option<T>,
|
||||
port: u16,
|
||||
|
@@ -20,7 +20,7 @@ pub enum ConnectError {
|
||||
#[display(fmt = "Connector received `Connect` method with unresolved host")]
|
||||
Unresolved,
|
||||
|
||||
/// Connection io error
|
||||
/// Connection IO error
|
||||
#[display(fmt = "{}", _0)]
|
||||
Io(io::Error),
|
||||
}
|
||||
|
@@ -1,11 +1,11 @@
|
||||
//! Actix connect - tcp connector service
|
||||
//! TCP connector service for Actix ecosystem.
|
||||
//!
|
||||
//! ## Package feature
|
||||
//!
|
||||
//! * `openssl` - enables ssl support via `openssl` crate
|
||||
//! * `rustls` - enables ssl support via `rustls` crate
|
||||
#![deny(rust_2018_idioms, warnings)]
|
||||
#![allow(clippy::type_complexity)]
|
||||
//! * `openssl` - enables TLS support via `openssl` crate
|
||||
//! * `rustls` - enables TLS support via `rustls` crate
|
||||
|
||||
#![deny(rust_2018_idioms)]
|
||||
#![recursion_limit = "128"]
|
||||
|
||||
#[macro_use]
|
||||
@@ -71,7 +71,7 @@ pub async fn start_default_resolver() -> Result<AsyncResolver, ConnectError> {
|
||||
get_default_resolver().await
|
||||
}
|
||||
|
||||
/// Create tcp connector service
|
||||
/// Create TCP connector service.
|
||||
pub fn new_connector<T: Address + 'static>(
|
||||
resolver: AsyncResolver,
|
||||
) -> impl Service<Request = Connect<T>, Response = Connection<T, TcpStream>, Error = ConnectError>
|
||||
@@ -79,7 +79,7 @@ pub fn new_connector<T: Address + 'static>(
|
||||
pipeline(Resolver::new(resolver)).and_then(TcpConnector::new())
|
||||
}
|
||||
|
||||
/// Create tcp connector service
|
||||
/// Create TCP connector service factory.
|
||||
pub fn new_connector_factory<T: Address + 'static>(
|
||||
resolver: AsyncResolver,
|
||||
) -> impl ServiceFactory<
|
||||
@@ -92,14 +92,14 @@ pub fn new_connector_factory<T: Address + 'static>(
|
||||
pipeline_factory(ResolverFactory::new(resolver)).and_then(TcpConnectorFactory::new())
|
||||
}
|
||||
|
||||
/// Create connector service with default parameters
|
||||
/// Create connector service with default parameters.
|
||||
pub fn default_connector<T: Address + 'static>(
|
||||
) -> impl Service<Request = Connect<T>, Response = Connection<T, TcpStream>, Error = ConnectError>
|
||||
+ Clone {
|
||||
pipeline(Resolver::default()).and_then(TcpConnector::new())
|
||||
}
|
||||
|
||||
/// Create connector service factory with default parameters
|
||||
/// Create connector service factory with default parameters.
|
||||
pub fn default_connector_factory<T: Address + 'static>() -> impl ServiceFactory<
|
||||
Config = (),
|
||||
Request = Connect<T>,
|
||||
|
@@ -106,6 +106,7 @@ impl<T: Address> Service for Resolver<T> {
|
||||
type Request = Connect<T>;
|
||||
type Response = Connect<T>;
|
||||
type Error = ConnectError;
|
||||
#[allow(clippy::type_complexity)]
|
||||
type Future = Either<
|
||||
Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>,
|
||||
Ready<Result<Connect<T>, Self::Error>>,
|
||||
|
@@ -114,6 +114,7 @@ enum ConnectState<T: Address> {
|
||||
}
|
||||
|
||||
impl<T: Address> ConnectState<T> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn poll(
|
||||
&mut self,
|
||||
cx: &mut Context<'_>,
|
||||
|
@@ -17,7 +17,7 @@ use crate::{
|
||||
Address, Connect, ConnectError, ConnectService, ConnectServiceFactory, Connection,
|
||||
};
|
||||
|
||||
/// Openssl connector factory
|
||||
/// OpenSSL connector factory
|
||||
pub struct OpensslConnector<T, U> {
|
||||
connector: SslConnector,
|
||||
_t: PhantomData<(T, U)>,
|
||||
@@ -97,6 +97,7 @@ where
|
||||
type Request = Connection<T, U>;
|
||||
type Response = Connection<T, SslStream<U>>;
|
||||
type Error = io::Error;
|
||||
#[allow(clippy::type_complexity)]
|
||||
type Future = Either<ConnectAsyncExt<T, U>, Ready<Result<Self::Response, Self::Error>>>;
|
||||
|
||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
@@ -164,7 +165,7 @@ impl<T> OpensslConnectServiceFactory<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct new connect service with custom dns resolver
|
||||
/// Construct new connect service with custom DNS resolver
|
||||
pub fn with_resolver(connector: SslConnector, resolver: AsyncResolver) -> Self {
|
||||
OpensslConnectServiceFactory {
|
||||
tcp: ConnectServiceFactory::with_resolver(resolver),
|
||||
@@ -172,7 +173,7 @@ impl<T> OpensslConnectServiceFactory<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct openssl connect service
|
||||
/// Construct OpenSSL connect service
|
||||
pub fn service(&self) -> OpensslConnectService<T> {
|
||||
OpensslConnectService {
|
||||
tcp: self.tcp.service(),
|
||||
|
@@ -88,9 +88,9 @@ async fn test_new_service() {
|
||||
assert_eq!(con.peer_addr().unwrap(), srv.addr());
|
||||
}
|
||||
|
||||
#[cfg(feature = "openssl")]
|
||||
#[cfg(all(feature = "openssl", feature = "uri"))]
|
||||
#[actix_rt::test]
|
||||
async fn test_uri() {
|
||||
async fn test_openssl_uri() {
|
||||
use std::convert::TryFrom;
|
||||
|
||||
let srv = TestServer::with(|| {
|
||||
@@ -107,7 +107,7 @@ async fn test_uri() {
|
||||
assert_eq!(con.peer_addr().unwrap(), srv.addr());
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustls")]
|
||||
#[cfg(all(feature = "rustls", feature = "uri"))]
|
||||
#[actix_rt::test]
|
||||
async fn test_rustls_uri() {
|
||||
use std::convert::TryFrom;
|
||||
|
@@ -1,3 +0,0 @@
|
||||
# actix-ioframe
|
||||
|
||||
**This crate has been deprecated and removed.**
|
@@ -1,5 +1,9 @@
|
||||
# CHANGES
|
||||
|
||||
## 0.1.3 - 2020-12-3
|
||||
|
||||
* Add `actix-reexport` feature
|
||||
|
||||
## 0.1.2 - 2020-05-18
|
||||
|
||||
### Changed
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "actix-macros"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
description = "Actix runtime macros"
|
||||
repository = "https://github.com/actix/actix-net"
|
||||
@@ -16,6 +16,9 @@ proc-macro = true
|
||||
quote = "1.0.3"
|
||||
syn = { version = "^1", features = ["full"] }
|
||||
|
||||
[features]
|
||||
actix-reexport = []
|
||||
|
||||
[dev-dependencies]
|
||||
actix-rt = "1.0"
|
||||
|
||||
|
@@ -33,14 +33,25 @@ pub fn main(_: TokenStream, item: TokenStream) -> TokenStream {
|
||||
|
||||
sig.asyncness = None;
|
||||
|
||||
(quote! {
|
||||
#(#attrs)*
|
||||
#vis #sig {
|
||||
actix_rt::System::new(stringify!(#name))
|
||||
.block_on(async move { #body })
|
||||
}
|
||||
})
|
||||
.into()
|
||||
if cfg!(feature = "actix-reexport") {
|
||||
(quote! {
|
||||
#(#attrs)*
|
||||
#vis #sig {
|
||||
actix::System::new(stringify!(#name))
|
||||
.block_on(async move { #body })
|
||||
}
|
||||
})
|
||||
.into()
|
||||
} else {
|
||||
(quote! {
|
||||
#(#attrs)*
|
||||
#vis #sig {
|
||||
actix_rt::System::new(stringify!(#name))
|
||||
.block_on(async move { #body })
|
||||
}
|
||||
})
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Marks async test function to be executed by actix runtime.
|
||||
|
@@ -1,5 +1,11 @@
|
||||
# Changes
|
||||
|
||||
## Unreleased - 2020-xx-xx
|
||||
|
||||
### Added
|
||||
|
||||
* Add `System::attach_to_tokio` method. [#173]
|
||||
|
||||
## [1.1.1] - 2020-04-30
|
||||
|
||||
### Fixed
|
||||
|
@@ -17,9 +17,11 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
actix-macros = "0.1.0"
|
||||
actix-threadpool = "0.3"
|
||||
futures-channel = { version = "0.3.4", default-features = false }
|
||||
futures-util = { version = "0.3.4", default-features = false, features = ["alloc"] }
|
||||
copyless = "0.1.4"
|
||||
futures-channel = "0.3.4"
|
||||
futures-util = { version = "0.3.4", default-features = false, features = ["alloc"] }
|
||||
smallvec = "1"
|
||||
tokio = { version = "0.2.6", default-features = false, features = ["rt-core", "rt-util", "io-driver", "tcp", "uds", "udp", "time", "signal", "stream"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "0.2.6", features = ["full"] }
|
||||
|
@@ -134,10 +134,7 @@ impl Arbiter {
|
||||
.unbounded_send(SystemCommand::RegisterArbiter(id, arb));
|
||||
|
||||
// run loop
|
||||
let _ = match rt.block_on(stop_rx) {
|
||||
Ok(code) => code,
|
||||
Err(_) => 1,
|
||||
};
|
||||
let _ = rt.block_on(stop_rx).unwrap_or(1);
|
||||
|
||||
// unregister arbiter
|
||||
let _ = System::current()
|
||||
|
@@ -137,7 +137,7 @@ impl AsyncSystemRunner {
|
||||
Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)),
|
||||
};
|
||||
Arbiter::stop_system();
|
||||
return res;
|
||||
res
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
|
@@ -15,9 +15,6 @@ pub use self::builder::{Builder, SystemRunner};
|
||||
pub use self::runtime::Runtime;
|
||||
pub use self::system::System;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use actix_threadpool as blocking;
|
||||
|
||||
/// Spawns a future on the current arbiter.
|
||||
///
|
||||
/// # Panics
|
||||
|
@@ -57,10 +57,59 @@ impl System {
|
||||
Self::builder().name(name).build()
|
||||
}
|
||||
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
/// Create new system using provided tokio Handle.
|
||||
/// Create new system using provided tokio `LocalSet`.
|
||||
///
|
||||
/// This method panics if it can not spawn system arbiter
|
||||
///
|
||||
/// Note: This method uses provided `LocalSet` to create a `System` future only.
|
||||
/// All the [`Arbiter`]s will be started in separate threads using their own tokio `Runtime`s.
|
||||
/// It means that using this method currently it is impossible to make `actix-rt` work in the
|
||||
/// alternative `tokio` `Runtime`s (e.g. provided by [`tokio_compat`]).
|
||||
///
|
||||
/// [`Arbiter`]: struct.Arbiter.html
|
||||
/// [`tokio_compat`]: https://crates.io/crates/tokio-compat
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::{runtime::Runtime, task::LocalSet};
|
||||
/// use actix_rt::System;
|
||||
/// use futures_util::future::try_join_all;
|
||||
///
|
||||
/// async fn run_application() {
|
||||
/// let first_task = tokio::spawn(async {
|
||||
/// // ...
|
||||
/// # println!("One task");
|
||||
/// # Ok::<(),()>(())
|
||||
/// });
|
||||
///
|
||||
/// let second_task = tokio::spawn(async {
|
||||
/// // ...
|
||||
/// # println!("Another task");
|
||||
/// # Ok::<(),()>(())
|
||||
/// });
|
||||
///
|
||||
/// try_join_all(vec![first_task, second_task])
|
||||
/// .await
|
||||
/// .expect("Some of the futures finished unexpectedly");
|
||||
/// }
|
||||
///
|
||||
///
|
||||
/// let mut runtime = tokio::runtime::Builder::new()
|
||||
/// .core_threads(2)
|
||||
/// .enable_all()
|
||||
/// .threaded_scheduler()
|
||||
/// .build()
|
||||
/// .unwrap();
|
||||
///
|
||||
///
|
||||
/// let actix_system_task = LocalSet::new();
|
||||
/// let sys = System::run_in_tokio("actix-main-system", &actix_system_task);
|
||||
/// actix_system_task.spawn_local(sys);
|
||||
///
|
||||
/// let rest_operations = run_application();
|
||||
/// runtime.block_on(actix_system_task.run_until(rest_operations));
|
||||
/// ```
|
||||
pub fn run_in_tokio<T: Into<String>>(
|
||||
name: T,
|
||||
local: &LocalSet,
|
||||
@@ -71,6 +120,77 @@ impl System {
|
||||
.run_nonblocking()
|
||||
}
|
||||
|
||||
/// Consume the provided tokio Runtime and start the `System` in it.
|
||||
/// This method will create a `LocalSet` object and occupy the current thread
|
||||
/// for the created `System` exclusively. All the other asynchronous tasks that
|
||||
/// should be executed as well must be aggregated into one future, provided as the last
|
||||
/// argument to this method.
|
||||
///
|
||||
/// Note: This method uses provided `Runtime` to create a `System` future only.
|
||||
/// All the [`Arbiter`]s will be started in separate threads using their own tokio `Runtime`s.
|
||||
/// It means that using this method currently it is impossible to make `actix-rt` work in the
|
||||
/// alternative `tokio` `Runtime`s (e.g. provided by `tokio_compat`).
|
||||
///
|
||||
/// [`Arbiter`]: struct.Arbiter.html
|
||||
/// [`tokio_compat`]: https://crates.io/crates/tokio-compat
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `name`: Name of the System
|
||||
/// - `runtime`: A tokio Runtime to run the system in.
|
||||
/// - `rest_operations`: A future to be executed in the runtime along with the System.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tokio::runtime::Runtime;
|
||||
/// use actix_rt::System;
|
||||
/// use futures_util::future::try_join_all;
|
||||
///
|
||||
/// async fn run_application() {
|
||||
/// let first_task = tokio::spawn(async {
|
||||
/// // ...
|
||||
/// # println!("One task");
|
||||
/// # Ok::<(),()>(())
|
||||
/// });
|
||||
///
|
||||
/// let second_task = tokio::spawn(async {
|
||||
/// // ...
|
||||
/// # println!("Another task");
|
||||
/// # Ok::<(),()>(())
|
||||
/// });
|
||||
///
|
||||
/// try_join_all(vec![first_task, second_task])
|
||||
/// .await
|
||||
/// .expect("Some of the futures finished unexpectedly");
|
||||
/// }
|
||||
///
|
||||
///
|
||||
/// let runtime = tokio::runtime::Builder::new()
|
||||
/// .core_threads(2)
|
||||
/// .enable_all()
|
||||
/// .threaded_scheduler()
|
||||
/// .build()
|
||||
/// .unwrap();
|
||||
///
|
||||
/// let rest_operations = run_application();
|
||||
/// System::attach_to_tokio("actix-main-system", runtime, rest_operations);
|
||||
/// ```
|
||||
pub fn attach_to_tokio<Fut, R>(
|
||||
name: impl Into<String>,
|
||||
mut runtime: tokio::runtime::Runtime,
|
||||
rest_operations: Fut,
|
||||
) -> R
|
||||
where
|
||||
Fut: std::future::Future<Output = R>,
|
||||
{
|
||||
let actix_system_task = LocalSet::new();
|
||||
let sys = System::run_in_tokio(name.into(), &actix_system_task);
|
||||
actix_system_task.spawn_local(sys);
|
||||
|
||||
runtime.block_on(actix_system_task.run_until(rest_operations))
|
||||
}
|
||||
|
||||
/// Get current running system.
|
||||
pub fn current() -> System {
|
||||
CURRENT.with(|cell| match *cell.borrow() {
|
||||
|
@@ -1,210 +1,129 @@
|
||||
# Changes
|
||||
|
||||
## [1.0.3] - 2020-05-19
|
||||
## Unreleased - 2020-xx-xx
|
||||
* Added explicit info log message on accept queue pause. [#215]
|
||||
|
||||
### Changed
|
||||
|
||||
## 1.0.4 - 2020-09-12
|
||||
* Update actix-codec to 0.3.0.
|
||||
* Workers must be greater than 0. [#167]
|
||||
|
||||
[#167]: https://github.com/actix/actix-net/pull/167
|
||||
|
||||
|
||||
## 1.0.3 - 2020-05-19
|
||||
* Replace deprecated `net2` crate with `socket2` [#140]
|
||||
|
||||
[#140]: https://github.com/actix/actix-net/pull/140
|
||||
|
||||
## [1.0.2] - 2020-02-26
|
||||
|
||||
### Fixed
|
||||
|
||||
## 1.0.2 - 2020-02-26
|
||||
* Avoid error by calling `reregister()` on Windows [#103]
|
||||
|
||||
[#103]: https://github.com/actix/actix-net/pull/103
|
||||
|
||||
## [1.0.1] - 2019-12-29
|
||||
|
||||
### Changed
|
||||
|
||||
## 1.0.1 - 2019-12-29
|
||||
* Rename `.start()` method to `.run()`
|
||||
|
||||
## [1.0.0] - 2019-12-11
|
||||
|
||||
### Changed
|
||||
|
||||
## 1.0.0 - 2019-12-11
|
||||
* Use actix-net releases
|
||||
|
||||
|
||||
## [1.0.0-alpha.4] - 2019-12-08
|
||||
|
||||
### Changed
|
||||
|
||||
## 1.0.0-alpha.4 - 2019-12-08
|
||||
* Use actix-service 1.0.0-alpha.4
|
||||
|
||||
## [1.0.0-alpha.3] - 2019-12-07
|
||||
|
||||
### Changed
|
||||
|
||||
## 1.0.0-alpha.3 - 2019-12-07
|
||||
* Migrate to tokio 0.2
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fix compilation on non-unix platforms
|
||||
|
||||
* Better handling server configuration
|
||||
|
||||
|
||||
## [1.0.0-alpha.2] - 2019-12-02
|
||||
|
||||
### Changed
|
||||
|
||||
## 1.0.0-alpha.2 - 2019-12-02
|
||||
* Simplify server service (remove actix-server-config)
|
||||
|
||||
* Allow to wait on `Server` until server stops
|
||||
|
||||
|
||||
## [0.8.0-alpha.1] - 2019-11-22
|
||||
|
||||
### Changed
|
||||
|
||||
## 0.8.0-alpha.1 - 2019-11-22
|
||||
* Migrate to `std::future`
|
||||
|
||||
|
||||
## [0.7.0] - 2019-10-04
|
||||
|
||||
### Changed
|
||||
|
||||
## 0.7.0 - 2019-10-04
|
||||
* Update `rustls` to 0.16
|
||||
* Minimum required Rust version upped to 1.37.0
|
||||
|
||||
|
||||
## [0.6.1] - 2019-09-25
|
||||
|
||||
### Added
|
||||
|
||||
## 0.6.1 - 2019-09-25
|
||||
* Add UDS listening support to `ServerBuilder`
|
||||
|
||||
|
||||
## [0.6.0] - 2019-07-18
|
||||
|
||||
### Added
|
||||
|
||||
## 0.6.0 - 2019-07-18
|
||||
* Support Unix domain sockets #3
|
||||
|
||||
|
||||
## [0.5.1] - 2019-05-18
|
||||
|
||||
### Changed
|
||||
|
||||
## 0.5.1 - 2019-05-18
|
||||
* ServerBuilder::shutdown_timeout() accepts u64
|
||||
|
||||
|
||||
## [0.5.0] - 2019-05-12
|
||||
|
||||
### Added
|
||||
|
||||
## 0.5.0 - 2019-05-12
|
||||
* Add `Debug` impl for `SslError`
|
||||
|
||||
* Derive debug for `Server` and `ServerCommand`
|
||||
|
||||
### Changed
|
||||
|
||||
* Upgrade to actix-service 0.4
|
||||
|
||||
|
||||
## [0.4.3] - 2019-04-16
|
||||
|
||||
### Added
|
||||
|
||||
## 0.4.3 - 2019-04-16
|
||||
* Re-export `IoStream` trait
|
||||
|
||||
### Changed
|
||||
|
||||
* Deppend on `ssl` and `rust-tls` features from actix-server-config
|
||||
* Depend on `ssl` and `rust-tls` features from actix-server-config
|
||||
|
||||
|
||||
## [0.4.2] - 2019-03-30
|
||||
|
||||
### Fixed
|
||||
|
||||
## 0.4.2 - 2019-03-30
|
||||
* Fix SIGINT force shutdown
|
||||
|
||||
|
||||
## [0.4.1] - 2019-03-14
|
||||
|
||||
### Added
|
||||
|
||||
## 0.4.1 - 2019-03-14
|
||||
* `SystemRuntime::on_start()` - allow to run future before server service initialization
|
||||
|
||||
|
||||
## [0.4.0] - 2019-03-12
|
||||
|
||||
### Changed
|
||||
|
||||
## 0.4.0 - 2019-03-12
|
||||
* Use `ServerConfig` for service factory
|
||||
|
||||
* Wrap tcp socket to `Io` type
|
||||
|
||||
* Upgrade actix-service
|
||||
|
||||
|
||||
## [0.3.1] - 2019-03-04
|
||||
|
||||
### Added
|
||||
|
||||
## 0.3.1 - 2019-03-04
|
||||
* Add `ServerBuilder::maxconnrate` sets the maximum per-worker number of concurrent connections
|
||||
|
||||
* Add helper ssl error `SslError`
|
||||
|
||||
|
||||
### Changed
|
||||
|
||||
* Rename `StreamServiceFactory` to `ServiceFactory`
|
||||
|
||||
* Deprecate `StreamServiceFactory`
|
||||
|
||||
|
||||
## [0.3.0] - 2019-03-02
|
||||
|
||||
### Changed
|
||||
|
||||
## 0.3.0 - 2019-03-02
|
||||
* Use new `NewService` trait
|
||||
|
||||
|
||||
## [0.2.1] - 2019-02-09
|
||||
|
||||
### Changed
|
||||
|
||||
## 0.2.1 - 2019-02-09
|
||||
* Drop service response
|
||||
|
||||
|
||||
## [0.2.0] - 2019-02-01
|
||||
|
||||
### Changed
|
||||
|
||||
## 0.2.0 - 2019-02-01
|
||||
* Migrate to actix-service 0.2
|
||||
|
||||
* Updated rustls dependency
|
||||
|
||||
|
||||
## [0.1.3] - 2018-12-21
|
||||
|
||||
### Fixed
|
||||
|
||||
## 0.1.3 - 2018-12-21
|
||||
* Fix max concurrent connections handling
|
||||
|
||||
|
||||
## [0.1.2] - 2018-12-12
|
||||
|
||||
### Changed
|
||||
|
||||
## 0.1.2 - 2018-12-12
|
||||
* rename ServiceConfig::rt() to ServiceConfig::apply()
|
||||
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fix back-pressure for concurrent ssl handshakes
|
||||
|
||||
|
||||
## [0.1.1] - 2018-12-11
|
||||
|
||||
## 0.1.1 - 2018-12-11
|
||||
* Fix signal handling on windows
|
||||
|
||||
|
||||
## [0.1.0] - 2018-12-09
|
||||
|
||||
## 0.1.0 - 2018-12-09
|
||||
* Move server to separate crate
|
||||
|
@@ -1,8 +1,8 @@
|
||||
[package]
|
||||
name = "actix-server"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
description = "Actix server - General purpose tcp server"
|
||||
description = "General purpose TCP server built for the Actix ecosystem"
|
||||
keywords = ["network", "framework", "async", "futures"]
|
||||
homepage = "https://actix.rs"
|
||||
repository = "https://github.com/actix/actix-net.git"
|
||||
@@ -11,7 +11,6 @@ categories = ["network-programming", "asynchronous"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
exclude = [".gitignore", ".cargo/config"]
|
||||
edition = "2018"
|
||||
workspace = ".."
|
||||
|
||||
[lib]
|
||||
name = "actix_server"
|
||||
@@ -21,13 +20,13 @@ path = "src/lib.rs"
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
actix-service = "1.0.1"
|
||||
actix-rt = "1.0.0"
|
||||
actix-codec = "0.2.0"
|
||||
actix-utils = "1.0.4"
|
||||
actix-service = "1.0.6"
|
||||
actix-rt = "1.1.1"
|
||||
actix-codec = "0.3.0"
|
||||
actix-utils = "2.0.0"
|
||||
|
||||
log = "0.4"
|
||||
num_cpus = "1.11"
|
||||
num_cpus = "1.13"
|
||||
mio = "0.6.19"
|
||||
socket2 = "0.3"
|
||||
futures-channel = { version = "0.3.4", default-features = false }
|
||||
@@ -42,3 +41,4 @@ mio-uds = { version = "0.6.7" }
|
||||
bytes = "0.5"
|
||||
env_logger = "0.7"
|
||||
actix-testing = "1.0.0"
|
||||
tokio = { version = "0.2", features = ["io-util"] }
|
||||
|
88
actix-server/examples/basic.rs
Normal file
88
actix-server/examples/basic.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
//! Simple composite-service TCP echo server.
|
||||
//!
|
||||
//! Using the following command:
|
||||
//!
|
||||
//! ```sh
|
||||
//! nc 127.0.0.1 8080
|
||||
//! ```
|
||||
//!
|
||||
//! Start typing. When you press enter the typed line will be echoed back. The server will log
|
||||
//! the length of each line it echos and the total size of data sent when the connection is closed.
|
||||
|
||||
use std::sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
Arc,
|
||||
};
|
||||
use std::{env, io};
|
||||
|
||||
use actix_rt::net::TcpStream;
|
||||
use actix_server::Server;
|
||||
use actix_service::pipeline_factory;
|
||||
use bytes::BytesMut;
|
||||
use futures_util::future::ok;
|
||||
use log::{error, info};
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
|
||||
#[actix_rt::main]
|
||||
async fn main() -> io::Result<()> {
|
||||
env::set_var("RUST_LOG", "actix=trace,basic=trace");
|
||||
env_logger::init();
|
||||
|
||||
let count = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
let addr = ("127.0.0.1", 8080);
|
||||
info!("starting server on port: {}", &addr.0);
|
||||
|
||||
// Bind socket address and start worker(s). By default, the server uses the number of available
|
||||
// logical CPU cores as the worker count. For this reason, the closure passed to bind needs
|
||||
// to return a service *factory*; so it can be created once per worker.
|
||||
Server::build()
|
||||
.bind("echo", addr, move || {
|
||||
let count = Arc::clone(&count);
|
||||
let num2 = Arc::clone(&count);
|
||||
|
||||
pipeline_factory(move |mut stream: TcpStream| {
|
||||
let count = Arc::clone(&count);
|
||||
|
||||
async move {
|
||||
let num = count.fetch_add(1, Ordering::SeqCst);
|
||||
let num = num + 1;
|
||||
|
||||
let mut size = 0;
|
||||
let mut buf = BytesMut::new();
|
||||
|
||||
loop {
|
||||
match stream.read_buf(&mut buf).await {
|
||||
// end of stream; bail from loop
|
||||
Ok(0) => break,
|
||||
|
||||
// more bytes to process
|
||||
Ok(bytes_read) => {
|
||||
info!("[{}] read {} bytes", num, bytes_read);
|
||||
stream.write_all(&buf[size..]).await.unwrap();
|
||||
size += bytes_read;
|
||||
}
|
||||
|
||||
// stream error; bail from loop with error
|
||||
Err(err) => {
|
||||
error!("Stream Error: {:?}", err);
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// send data down service pipeline
|
||||
Ok((buf.freeze(), size))
|
||||
}
|
||||
})
|
||||
.map_err(|err| error!("Service Error: {:?}", err))
|
||||
.and_then(move |(_, size)| {
|
||||
let num = num2.load(Ordering::SeqCst);
|
||||
info!("[{}] total bytes read: {}", num, size);
|
||||
ok(size)
|
||||
})
|
||||
})?
|
||||
.workers(1)
|
||||
.run()
|
||||
.await
|
||||
}
|
@@ -381,6 +381,7 @@ impl Accept {
|
||||
self.backpressure = true;
|
||||
for (_, info) in self.sockets.iter() {
|
||||
let _ = self.poll.deregister(&info.sock);
|
||||
info!("Accepting connections on {} has been paused", info.addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -72,8 +72,9 @@ impl ServerBuilder {
|
||||
/// Set number of workers to start.
|
||||
///
|
||||
/// By default server uses number of available logical cpu as workers
|
||||
/// count.
|
||||
/// count. Workers must be greater than 0.
|
||||
pub fn workers(mut self, num: usize) -> Self {
|
||||
assert_ne!(num, 0, "workers must be greater than 0");
|
||||
self.threads = num;
|
||||
self
|
||||
}
|
||||
|
@@ -151,7 +151,7 @@ impl InternalServiceFactory for ConfiguredService {
|
||||
));
|
||||
};
|
||||
}
|
||||
return Ok(res);
|
||||
Ok(res)
|
||||
}
|
||||
.boxed_local()
|
||||
}
|
||||
@@ -272,13 +272,13 @@ where
|
||||
fn new_service(&self, _: ()) -> Self::Future {
|
||||
let fut = self.inner.new_service(());
|
||||
async move {
|
||||
return match fut.await {
|
||||
match fut.await {
|
||||
Ok(s) => Ok(Box::new(StreamService::new(s)) as BoxedServerService),
|
||||
Err(e) => {
|
||||
error!("Can not construct service: {:?}", e);
|
||||
Err(())
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
.boxed_local()
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
//! General purpose tcp server
|
||||
#![deny(rust_2018_idioms, warnings)]
|
||||
#![allow(clippy::type_complexity)]
|
||||
//! General purpose TCP server.
|
||||
|
||||
#![deny(rust_2018_idioms)]
|
||||
|
||||
mod accept;
|
||||
mod builder;
|
||||
@@ -19,7 +19,7 @@ pub use self::service::ServiceFactory;
|
||||
#[doc(hidden)]
|
||||
pub use self::socket::FromStream;
|
||||
|
||||
/// Socket id token
|
||||
/// Socket ID token
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct Token(usize);
|
||||
|
||||
|
@@ -17,8 +17,10 @@ use crate::socket::{FromStream, StdStream};
|
||||
pub(crate) enum ServerMessage {
|
||||
/// New stream
|
||||
Connect(StdStream),
|
||||
/// Gracefull shutdown
|
||||
|
||||
/// Gracefully shutdown
|
||||
Shutdown(Duration),
|
||||
|
||||
/// Force shutdown
|
||||
ForceShutdown,
|
||||
}
|
||||
|
@@ -303,6 +303,7 @@ enum WorkerState {
|
||||
Restarting(
|
||||
usize,
|
||||
Token,
|
||||
#[allow(clippy::type_complexity)]
|
||||
Pin<Box<dyn Future<Output = Result<Vec<(Token, BoxedServerService)>, ()>>>>,
|
||||
),
|
||||
Shutdown(
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# Changes
|
||||
|
||||
## Unreleased - 2020-xx-xx
|
||||
|
||||
* Upgrade `pin-project` to `1.0`.
|
||||
|
||||
## 1.0.6 - 2020-08-09
|
||||
|
||||
|
@@ -18,7 +18,7 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
futures-util = "0.3.1"
|
||||
pin-project = "0.4.17"
|
||||
pin-project = "1.0.0"
|
||||
|
||||
[dev-dependencies]
|
||||
actix-rt = "1.0.0"
|
||||
|
@@ -2,6 +2,6 @@
|
||||
|
||||
> Service trait and combinators for representing asynchronous request/response operations.
|
||||
|
||||
See documentation for detailed explanations these components: [https://docs.rs/actix-service](docs).
|
||||
See documentation for detailed explanations these components: [https://docs.rs/actix-service][docs].
|
||||
|
||||
[docs]: https://docs.rs/actix-service
|
||||
|
@@ -9,7 +9,7 @@ use super::{Service, ServiceFactory};
|
||||
/// Service for the `and_then` combinator, chaining a computation onto the end
|
||||
/// of another service which completes successfully.
|
||||
///
|
||||
/// This is created by the `ServiceExt::and_then` method.
|
||||
/// This is created by the `Pipeline::and_then` method.
|
||||
pub(crate) struct AndThenService<A, B>(Rc<RefCell<(A, B)>>);
|
||||
|
||||
impl<A, B> AndThenService<A, B> {
|
||||
|
@@ -5,7 +5,7 @@ use std::task::{Context, Poll};
|
||||
|
||||
use super::{IntoService, IntoServiceFactory, Service, ServiceFactory};
|
||||
|
||||
/// Apply tranform function to a service.
|
||||
/// Apply transform function to a service.
|
||||
pub fn apply_fn<T, F, R, In, Out, Err, U>(service: U, f: F) -> Apply<T, F, R, In, Out, Err>
|
||||
where
|
||||
T: Service<Error = Err>,
|
||||
@@ -16,7 +16,7 @@ where
|
||||
Apply::new(service.into_service(), f)
|
||||
}
|
||||
|
||||
/// Service factory that prodices `apply_fn` service.
|
||||
/// Service factory that produces `apply_fn` service.
|
||||
pub fn apply_fn_factory<T, F, R, In, Out, Err, U>(
|
||||
service: U,
|
||||
f: F,
|
||||
|
@@ -9,7 +9,7 @@ use crate::map_init_err::MapInitErr;
|
||||
use crate::then::{ThenService, ThenServiceFactory};
|
||||
use crate::{IntoService, IntoServiceFactory, Service, ServiceFactory};
|
||||
|
||||
/// Contruct new pipeline with one service in pipeline chain.
|
||||
/// Construct new pipeline with one service in pipeline chain.
|
||||
pub fn pipeline<F, T>(service: F) -> Pipeline<T>
|
||||
where
|
||||
F: IntoService<T>,
|
||||
@@ -20,7 +20,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Contruct new pipeline factory with one service factory.
|
||||
/// Construct new pipeline factory with one service factory.
|
||||
pub fn pipeline_factory<T, F>(factory: F) -> PipelineFactory<T>
|
||||
where
|
||||
T: ServiceFactory,
|
||||
|
@@ -70,7 +70,7 @@ where
|
||||
/// timeout: Duration,
|
||||
/// }
|
||||
///
|
||||
/// impl<S> Transform<S> for TimeoutTransform<E>
|
||||
/// impl<S> Transform<S> for TimeoutTransform
|
||||
/// where
|
||||
/// S: Service,
|
||||
/// {
|
||||
@@ -115,7 +115,7 @@ pub trait Transform<S> {
|
||||
/// Creates and returns a new Transform component, asynchronously
|
||||
fn new_transform(&self, service: S) -> Self::Future;
|
||||
|
||||
/// Map this transforms's factory error to a different error,
|
||||
/// Map this transform's factory error to a different error,
|
||||
/// returning a new transform service factory.
|
||||
fn map_init_err<F, E>(self, f: F) -> TransformMapInitErr<Self, S, F, E>
|
||||
where
|
||||
|
@@ -37,7 +37,7 @@ pub use actix_macros::test;
|
||||
/// ```
|
||||
pub struct TestServer;
|
||||
|
||||
/// Test server runstime
|
||||
/// Test server runtime
|
||||
pub struct TestServerRuntime {
|
||||
addr: net::SocketAddr,
|
||||
host: String,
|
||||
@@ -107,7 +107,7 @@ impl TestServer {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get firat available unused local address
|
||||
/// Get first available unused local address
|
||||
pub fn unused_addr() -> net::SocketAddr {
|
||||
let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap();
|
||||
let socket =
|
||||
|
@@ -1,39 +1,37 @@
|
||||
# Changes
|
||||
|
||||
## Unreleased
|
||||
## Unreleased - 2020-xx-xx
|
||||
|
||||
|
||||
## 2.0.0 - 2020-09-03
|
||||
* `nativetls::NativeTlsAcceptor` is renamed to `nativetls::Acceptor`.
|
||||
* Where possible, "SSL" terminology is replaced with "TLS".
|
||||
* `SslError` is renamed to `TlsError`.
|
||||
* `TlsError::Ssl` enum variant is renamed to `TlsError::Tls`.
|
||||
* `max_concurrent_ssl_connect` is renamed to `max_concurrent_tls_connect`.
|
||||
|
||||
|
||||
## 2.0.0-alpha.2 - 2020-08-17
|
||||
|
||||
### Changed
|
||||
|
||||
* Update `rustls` dependency to 0.18
|
||||
* Update `tokio-rustls` dependency to 0.14
|
||||
* Update `webpki-roots` dependency to 0.20
|
||||
|
||||
|
||||
## [2.0.0-alpha.1] - 2020-03-03
|
||||
|
||||
### Changed
|
||||
|
||||
* Update `rustls` dependency to 0.17
|
||||
* Update `tokio-rustls` dependency to 0.13
|
||||
* Update `webpki-roots` dependency to 0.19
|
||||
|
||||
## [1.0.0] - 2019-12-11
|
||||
|
||||
## [1.0.0] - 2019-12-11
|
||||
* 1.0.0 release
|
||||
|
||||
|
||||
## [1.0.0-alpha.3] - 2019-12-07
|
||||
|
||||
### Changed
|
||||
|
||||
* Migrate to tokio 0.2
|
||||
|
||||
* Enable rustls acceptor service
|
||||
|
||||
* Enable native-tls acceptor service
|
||||
|
||||
## [1.0.0-alpha.1] - 2019-12-02
|
||||
|
||||
* Split openssl accetor from actix-server package
|
||||
## [1.0.0-alpha.1] - 2019-12-02
|
||||
* Split openssl acceptor from actix-server package
|
||||
|
@@ -1,16 +1,15 @@
|
||||
[package]
|
||||
name = "actix-tls"
|
||||
version = "2.0.0-alpha.2"
|
||||
version = "2.0.0"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
description = "Actix tls services"
|
||||
keywords = ["network", "framework", "async", "futures"]
|
||||
description = "TLS acceptor services for Actix ecosystem."
|
||||
keywords = ["network", "framework", "async", "tls", "ssl"]
|
||||
homepage = "https://actix.rs"
|
||||
repository = "https://github.com/actix/actix-net.git"
|
||||
documentation = "https://docs.rs/actix-tls/"
|
||||
categories = ["network-programming", "asynchronous"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2018"
|
||||
workspace = ".."
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["openssl", "rustls", "nativetls"]
|
||||
@@ -19,6 +18,10 @@ features = ["openssl", "rustls", "nativetls"]
|
||||
name = "actix_tls"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[example]]
|
||||
name = "basic"
|
||||
required-features = ["rustls"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@@ -33,28 +36,29 @@ nativetls = ["native-tls", "tokio-tls"]
|
||||
|
||||
[dependencies]
|
||||
actix-service = "1.0.0"
|
||||
actix-codec = "0.2.0"
|
||||
actix-utils = "1.0.0"
|
||||
actix-rt = "1.0.0"
|
||||
derive_more = "0.99.2"
|
||||
either = "1.5.2"
|
||||
actix-codec = "0.3.0"
|
||||
actix-utils = "2.0.0"
|
||||
|
||||
futures-util = { version = "0.3.4", default-features = false }
|
||||
log = "0.4"
|
||||
|
||||
# openssl
|
||||
open-ssl = { version="0.10", package = "openssl", optional = true }
|
||||
open-ssl = { package = "openssl", version = "0.10", optional = true }
|
||||
tokio-openssl = { version = "0.4.0", optional = true }
|
||||
|
||||
# rustls
|
||||
rust-tls = { version = "0.18.0", package = "rustls", optional = true }
|
||||
rust-tls = { package = "rustls", version = "0.18.0", optional = true }
|
||||
webpki = { version = "0.21", optional = true }
|
||||
webpki-roots = { version = "0.20", optional = true }
|
||||
tokio-rustls = { version = "0.14.0", optional = true }
|
||||
|
||||
# native-tls
|
||||
native-tls = { version="0.2", optional = true }
|
||||
tokio-tls = { version="0.3", optional = true }
|
||||
native-tls = { version = "0.2", optional = true }
|
||||
tokio-tls = { version = "0.3", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
bytes = "0.5"
|
||||
actix-testing = { version="1.0.0" }
|
||||
log = "0.4"
|
||||
env_logger = "0.7"
|
||||
actix-testing = "1.0.0"
|
||||
actix-server = "1"
|
||||
actix-rt = "1"
|
||||
|
82
actix-tls/examples/basic.rs
Normal file
82
actix-tls/examples/basic.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
//! TLS Acceptor Server
|
||||
//!
|
||||
//! Using either HTTPie (`http`) or cURL:
|
||||
//!
|
||||
//! This commands will produce errors in the server log:
|
||||
//! ```sh
|
||||
//! curl 127.0.0.1:8443
|
||||
//! http 127.0.0.1:8443
|
||||
//! ```
|
||||
//!
|
||||
//! These commands will show "empty reply" on the client but will debug print the TLS stream info
|
||||
//! in the server log, indicating a successful TLS handshake:
|
||||
//! ```sh
|
||||
//! curl -k https://127.0.0.1:8443
|
||||
//! http --verify=false https://127.0.0.1:8443
|
||||
//! ```
|
||||
|
||||
use std::{
|
||||
env,
|
||||
fs::File,
|
||||
io::{self, BufReader},
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
Arc,
|
||||
},
|
||||
};
|
||||
|
||||
use actix_server::Server;
|
||||
use actix_service::pipeline_factory;
|
||||
use actix_tls::rustls::Acceptor as RustlsAcceptor;
|
||||
use futures_util::future::ok;
|
||||
use log::info;
|
||||
use rust_tls::{
|
||||
internal::pemfile::certs, internal::pemfile::rsa_private_keys, NoClientAuth, ServerConfig,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ServiceState {
|
||||
num: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
#[actix_rt::main]
|
||||
async fn main() -> io::Result<()> {
|
||||
env::set_var("RUST_LOG", "actix=trace,basic=trace");
|
||||
env_logger::init();
|
||||
|
||||
let mut tls_config = ServerConfig::new(NoClientAuth::new());
|
||||
|
||||
// Load TLS key and cert files
|
||||
let cert_file = &mut BufReader::new(File::open("./examples/cert.pem").unwrap());
|
||||
let key_file = &mut BufReader::new(File::open("./examples/key.pem").unwrap());
|
||||
|
||||
let cert_chain = certs(cert_file).unwrap();
|
||||
let mut keys = rsa_private_keys(key_file).unwrap();
|
||||
tls_config
|
||||
.set_single_cert(cert_chain, keys.remove(0))
|
||||
.unwrap();
|
||||
|
||||
let tls_acceptor = RustlsAcceptor::new(tls_config);
|
||||
|
||||
let count = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
let addr = ("127.0.0.1", 8443);
|
||||
info!("starting server on port: {}", &addr.0);
|
||||
|
||||
Server::build()
|
||||
.bind("tls-example", addr, move || {
|
||||
let count = Arc::clone(&count);
|
||||
|
||||
// Set up TLS service factory
|
||||
pipeline_factory(tls_acceptor.clone())
|
||||
.map_err(|err| println!("Rustls error: {:?}", err))
|
||||
.and_then(move |stream| {
|
||||
let num = count.fetch_add(1, Ordering::Relaxed);
|
||||
info!("[{}] Got TLS connection: {:?}", num, stream);
|
||||
ok(())
|
||||
})
|
||||
})?
|
||||
.workers(1)
|
||||
.run()
|
||||
.await
|
||||
}
|
25
actix-tls/examples/cert.pem
Normal file
25
actix-tls/examples/cert.pem
Normal file
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIENjCCAp6gAwIBAgIRANp+D9pBErdacw6KjrwJ+4swDQYJKoZIhvcNAQELBQAw
|
||||
bTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSEwHwYDVQQLDBhyb2JA
|
||||
c29tYnJhLng1Mi5kZXYgKFJvYikxKDAmBgNVBAMMH21rY2VydCByb2JAc29tYnJh
|
||||
Lng1Mi5kZXYgKFJvYikwHhcNMTkwNjAxMDAwMDAwWhcNMzAwOTEzMDIzNDI0WjBM
|
||||
MScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxvcG1lbnQgY2VydGlmaWNhdGUxITAfBgNV
|
||||
BAsMGHJvYkBzb21icmEueDUyLmRldiAoUm9iKTCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBALYAn8dsQUDTp8SptAtkiAySvQYLpAOct3/OjBn+dSYfbQcp
|
||||
Ph9w/Zo83Msl7Fb1DBvADHFtyBpESATZ2chS5fwCAwUFTlKrzMk3qauEoJ3cCQa8
|
||||
ccqhTMLeT38jRlhXrMHWBfz0ipqy+yTLWeM32LX8s0jPbbsZ3gVJ/Ls4qm0CTaqb
|
||||
zRdcQ7GTVKYet5DR7ZvwvAaLtWk/iiHKwnOveuF27HNlxj0Rwd/lhJ/t9x8xJwyR
|
||||
MTdm852KQadI8xOSbWNK4j9419yzKjUEMKgn78wT/7DQfeKKCAreHa4MaEw4+koD
|
||||
2Bqb+V4fI6T84VvXkNG3CjSpmIiYGlIE1LVgBL8CAwEAAaNyMHAwDgYDVR0PAQH/
|
||||
BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHwYDVR0j
|
||||
BBgwFoAUto/ox0MqZShmQpViV/gjfJKrMDkwGgYDVR0RBBMwEYIJbG9jYWxob3N0
|
||||
hwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBgQBUCMzqTY0sg+61gh8gKS5TCL6qs0R1
|
||||
xys/EFFaD5JYUsfM/HyhHd0jq+x5Pd3mB2Jvhoq9xhjMwP11H8Uw5lLBHA8USdF9
|
||||
EiLW1GvT3/gLfMqb0lPk0RMRBeX8c0QbDtqdiUCE7S6zJbZ5gjFeRuFNjdcGA1Ss
|
||||
8CPPts2mns5cwah6H7T/BFzj5aR9Qe14vo1Rpr5gD5CpHvk1t16q7YsczQfVMvt3
|
||||
Ydk6p0rwA8Z5okQK7y3qKPZI+//ygWL6ZBjVjl1/Al8vybG2UYjYgfMBwaVvMiDJ
|
||||
j/vCdVmlvGb+MZlZID/p2veaNeEKgi1A1EOj3sNuQYXXFfSD9mdamX7JIfGi/U7v
|
||||
ivvUjJUbzGrUngldt5iCKqcCQum7nlzu9sT1Tm2t/n4tz/btrI+Wimg8riSzM+Nk
|
||||
dfuvv4NbWe6Th5460HH8mMvfPZSB8dCoxwm98tuqcMXLkR1RJX5Z8LYAaPTsUs/h
|
||||
HxQCY4EaY7feZ/qFal9FGwvpzVr3/XjgSCU=
|
||||
-----END CERTIFICATE-----
|
27
actix-tls/examples/key.pem
Normal file
27
actix-tls/examples/key.pem
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAtgCfx2xBQNOnxKm0C2SIDJK9BgukA5y3f86MGf51Jh9tByk+
|
||||
H3D9mjzcyyXsVvUMG8AMcW3IGkRIBNnZyFLl/AIDBQVOUqvMyTepq4SgndwJBrxx
|
||||
yqFMwt5PfyNGWFeswdYF/PSKmrL7JMtZ4zfYtfyzSM9tuxneBUn8uziqbQJNqpvN
|
||||
F1xDsZNUph63kNHtm/C8Bou1aT+KIcrCc6964Xbsc2XGPRHB3+WEn+33HzEnDJEx
|
||||
N2bznYpBp0jzE5JtY0riP3jX3LMqNQQwqCfvzBP/sNB94ooICt4drgxoTDj6SgPY
|
||||
Gpv5Xh8jpPzhW9eQ0bcKNKmYiJgaUgTUtWAEvwIDAQABAoIBADC0Zg21+Jhii6jj
|
||||
SR0rYAUNV6xAfTnCPJDlMzTZlXwIOOMLtGYxlIwr8WIj2eVDWmQqtqm8GSp+T0+N
|
||||
BOzI0mboGurDCryw4PKQBMWzjk/wTDITR9hT5fjYCSoaxH5rp/2PSrbwsg7ICtFD
|
||||
4eAeV84Lu+amK9VADNwZepqXhXP6EDOY5yovkwzOQNDM/qVzHSe9EoFP74M/oWnY
|
||||
ohIuWdZzwAZuTA5SUjPygiVzs/vhsrSE9crMIzr5VgKBi+C+ALkrL7Lc4GlRPI4r
|
||||
6VsbIxZHa7who+FhjZ0cVfdXHH47QDdf10X5bEXsaFBvGGCLtkQ3XEpov6GOlaH+
|
||||
aY7fzPECgYEA4LGloaMC9J27uyPxHkQwEehexmJdIu0vNUefv5yiO9PbvrjvYnh7
|
||||
JxRVgv1fy2bRMOvg19TujCYRZdkrLDqSDsfFfEiThvlFBRZfKKIHmWdyfvIe9Jp9
|
||||
rqdxhWAco7FoM+W6c8c4iR4xs8/GA60CVcAiTLqgPWWzn12fesiULi0CgYEAz1xD
|
||||
OulJyfpHVGQ6ZM1wR0SZ9H9GS3BenpL2ue5uBfe3hM+JIAAM61Y48wJuCWT5EvfL
|
||||
FgnH3oCo7SYGcgGkERS8H7k67DJCLlqDo/3FC7lX/irz+ya/FoZmKBagvjEUWhpe
|
||||
Bb2dRIbqsG0lsCzU9MVrgtvodD0MBTyt0RM5fhsCgYEAhgYQiLhGBAituLN4mBgO
|
||||
IDBdj7GOYk3dkcc2J0HTlyIIeduvlinNM4Myel6NrDKY5rhbtgGhhGEUkY6W7NvG
|
||||
0SAh0L8tmB3JKH6upfr3023b4pKjGj2oZ+wij27DxnQEdqg5reOP+mHTPbDaKMki
|
||||
kml3TBMpj1XBbXaXsNJBaMUCgYEAnnNzEC4563QrU2pvUJ3HgT4Dotgqv/Sy6NuG
|
||||
W1e9jSPYgU0RDHndZWtygwdFTDpzNbJR5po8t2J7MxQOcsmcNE0y387sHpbdCYyy
|
||||
8Po2uxm7CoaJ/02BUVYL8/Aujob0dVGWrS5SYY3zAjO1S+VGKXA+EjW2cDRB3jKa
|
||||
45ucICcCgYBdMxB5Oj6GpdewWWaBss9dwHtDaD4oVGYIBbIc2qdyCYixWdW9NccV
|
||||
fRJs0ulGrpg9OtyWbwZASu2jz55+s3hi4rnrcaXKiIh9Rs25v1irF6Dmduvo7CaN
|
||||
Mf7zBg7LUttmqN6D3npIAxmBULl8KRfjnt6U2tJolF5X0qQ1uqnnTA==
|
||||
-----END RSA PRIVATE KEY-----
|
@@ -1,6 +1,11 @@
|
||||
//! SSL Services
|
||||
#![deny(rust_2018_idioms, warnings)]
|
||||
#![allow(clippy::type_complexity)]
|
||||
//! TLS acceptor services for Actix ecosystem.
|
||||
//!
|
||||
//! ## Crate Features
|
||||
//! * `openssl` - TLS acceptor using the `openssl` crate.
|
||||
//! * `rustls` - TLS acceptor using the `rustls` crate.
|
||||
//! * `nativetls` - TLS acceptor using the `native-tls` crate.
|
||||
|
||||
#![deny(rust_2018_idioms)]
|
||||
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
@@ -15,25 +20,25 @@ pub mod rustls;
|
||||
#[cfg(feature = "nativetls")]
|
||||
pub mod nativetls;
|
||||
|
||||
/// Sets the maximum per-worker concurrent ssl connection establish process.
|
||||
///
|
||||
/// All listeners will stop accepting connections when this limit is
|
||||
/// reached. It can be used to limit the global SSL CPU usage.
|
||||
///
|
||||
/// By default max connections is set to a 256.
|
||||
pub fn max_concurrent_ssl_connect(num: usize) {
|
||||
MAX_CONN.store(num, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub(crate) static MAX_CONN: AtomicUsize = AtomicUsize::new(256);
|
||||
|
||||
thread_local! {
|
||||
static MAX_CONN_COUNTER: Counter = Counter::new(MAX_CONN.load(Ordering::Relaxed));
|
||||
}
|
||||
|
||||
/// Ssl error combinded with service error.
|
||||
/// Sets the maximum per-worker concurrent TLS connection limit.
|
||||
///
|
||||
/// All listeners will stop accepting connections when this limit is reached.
|
||||
/// It can be used to regulate the global TLS CPU usage.
|
||||
///
|
||||
/// By default, the connection limit is 256.
|
||||
pub fn max_concurrent_tls_connect(num: usize) {
|
||||
MAX_CONN.store(num, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// TLS error combined with service error.
|
||||
#[derive(Debug)]
|
||||
pub enum SslError<E1, E2> {
|
||||
Ssl(E1),
|
||||
pub enum TlsError<E1, E2> {
|
||||
Tls(E1),
|
||||
Service(E2),
|
||||
}
|
||||
|
@@ -5,34 +5,35 @@ use actix_codec::{AsyncRead, AsyncWrite};
|
||||
use actix_service::{Service, ServiceFactory};
|
||||
use actix_utils::counter::Counter;
|
||||
use futures_util::future::{self, FutureExt, LocalBoxFuture, TryFutureExt};
|
||||
|
||||
pub use native_tls::Error;
|
||||
pub use tokio_tls::{TlsAcceptor, TlsStream};
|
||||
|
||||
use crate::MAX_CONN_COUNTER;
|
||||
|
||||
/// Support `SSL` connections via native-tls package
|
||||
/// Accept TLS connections via `native-tls` package.
|
||||
///
|
||||
/// `tls` feature enables `NativeTlsAcceptor` type
|
||||
pub struct NativeTlsAcceptor<T> {
|
||||
/// `nativetls` feature enables this `Acceptor` type.
|
||||
pub struct Acceptor<T> {
|
||||
acceptor: TlsAcceptor,
|
||||
io: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> NativeTlsAcceptor<T>
|
||||
impl<T> Acceptor<T>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
{
|
||||
/// Create `NativeTlsAcceptor` instance
|
||||
/// Create `native-tls` based `Acceptor` service factory.
|
||||
#[inline]
|
||||
pub fn new(acceptor: TlsAcceptor) -> Self {
|
||||
NativeTlsAcceptor {
|
||||
Acceptor {
|
||||
acceptor,
|
||||
io: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for NativeTlsAcceptor<T> {
|
||||
impl<T> Clone for Acceptor<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
@@ -42,7 +43,7 @@ impl<T> Clone for NativeTlsAcceptor<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ServiceFactory for NativeTlsAcceptor<T>
|
||||
impl<T> ServiceFactory for Acceptor<T>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
{
|
||||
@@ -104,8 +105,7 @@ where
|
||||
let this = self.clone();
|
||||
async move { this.acceptor.accept(req).await }
|
||||
.map_ok(move |io| {
|
||||
// Required to preserve `CounterGuard` until `Self::Future`
|
||||
// is completely resolved.
|
||||
// Required to preserve `CounterGuard` until `Self::Future` is completely resolved.
|
||||
let _ = guard;
|
||||
io
|
||||
})
|
||||
|
@@ -3,26 +3,27 @@ use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
pub use open_ssl::ssl::{AlpnError, SslAcceptor, SslAcceptorBuilder};
|
||||
pub use tokio_openssl::{HandshakeError, SslStream};
|
||||
|
||||
use actix_codec::{AsyncRead, AsyncWrite};
|
||||
use actix_service::{Service, ServiceFactory};
|
||||
use actix_utils::counter::{Counter, CounterGuard};
|
||||
use futures_util::future::{ok, FutureExt, LocalBoxFuture, Ready};
|
||||
|
||||
pub use open_ssl::ssl::{AlpnError, SslAcceptor, SslAcceptorBuilder};
|
||||
pub use tokio_openssl::{HandshakeError, SslStream};
|
||||
|
||||
use crate::MAX_CONN_COUNTER;
|
||||
|
||||
/// Support `TLS` server connections via openssl package
|
||||
/// Accept TLS connections via `openssl` package.
|
||||
///
|
||||
/// `openssl` feature enables `Acceptor` type
|
||||
/// `openssl` feature enables this `Acceptor` type.
|
||||
pub struct Acceptor<T: AsyncRead + AsyncWrite> {
|
||||
acceptor: SslAcceptor,
|
||||
io: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: AsyncRead + AsyncWrite> Acceptor<T> {
|
||||
/// Create default `OpensslAcceptor`
|
||||
/// Create OpenSSL based `Acceptor` service factory.
|
||||
#[inline]
|
||||
pub fn new(acceptor: SslAcceptor) -> Self {
|
||||
Acceptor {
|
||||
acceptor,
|
||||
@@ -32,6 +33,7 @@ impl<T: AsyncRead + AsyncWrite> Acceptor<T> {
|
||||
}
|
||||
|
||||
impl<T: AsyncRead + AsyncWrite> Clone for Acceptor<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
acceptor: self.acceptor.clone(),
|
||||
|
@@ -17,16 +17,17 @@ pub use webpki_roots::TLS_SERVER_ROOTS;
|
||||
|
||||
use crate::MAX_CONN_COUNTER;
|
||||
|
||||
/// Support `SSL` connections via rustls package
|
||||
/// Accept TLS connections via `rustls` package.
|
||||
///
|
||||
/// `rust-tls` feature enables `RustlsAcceptor` type
|
||||
/// `rustls` feature enables this `Acceptor` type.
|
||||
pub struct Acceptor<T> {
|
||||
config: Arc<ServerConfig>,
|
||||
io: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: AsyncRead + AsyncWrite> Acceptor<T> {
|
||||
/// Create rustls based `Acceptor` service factory
|
||||
/// Create Rustls based `Acceptor` service factory.
|
||||
#[inline]
|
||||
pub fn new(config: ServerConfig) -> Self {
|
||||
Acceptor {
|
||||
config: Arc::new(config),
|
||||
@@ -36,6 +37,7 @@ impl<T: AsyncRead + AsyncWrite> Acceptor<T> {
|
||||
}
|
||||
|
||||
impl<T> Clone for Acceptor<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
config: self.config.clone(),
|
||||
@@ -65,7 +67,7 @@ impl<T: AsyncRead + AsyncWrite + Unpin> ServiceFactory for Acceptor<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// RusTLS based `Acceptor` service
|
||||
/// Rustls based `Acceptor` service
|
||||
pub struct AcceptorService<T> {
|
||||
acceptor: TlsAcceptor,
|
||||
io: PhantomData<T>,
|
||||
|
@@ -1,9 +1,15 @@
|
||||
# Changes
|
||||
|
||||
## Unreleased - 2020-xx-xx
|
||||
* Upgrade `pin-project` to `1.0`.
|
||||
|
||||
## 2.0.0 - 2020-08-23
|
||||
* No changes from beta 1.
|
||||
|
||||
## 2.0.0-beta.1 - 2020-08-19
|
||||
* Upgrade `tokio-util` to `0.3`.
|
||||
* Remove unsound custom Cell and use `std::cell::RefCell` instead, as well as `actix-service`.
|
||||
* Rename method to correctly spelled `LocalWaker::is_registered`.
|
||||
|
||||
## [1.0.6] - 2020-01-08
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
[package]
|
||||
name = "actix-utils"
|
||||
version = "1.0.6"
|
||||
version = "2.0.0"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
description = "Actix utils - various actix net related services"
|
||||
description = "Various network related services and utilities for the Actix ecosystem."
|
||||
keywords = ["network", "framework", "async", "futures"]
|
||||
homepage = "https://actix.rs"
|
||||
repository = "https://github.com/actix/actix-net.git"
|
||||
@@ -16,15 +16,15 @@ name = "actix_utils"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
actix-service = "1.0.1"
|
||||
actix-rt = "1.0.0"
|
||||
actix-codec = "0.2.0"
|
||||
bitflags = "1.2"
|
||||
actix-codec = "0.3.0"
|
||||
actix-rt = "1.1.1"
|
||||
actix-service = "1.0.6"
|
||||
bitflags = "1.2.1"
|
||||
bytes = "0.5.3"
|
||||
either = "1.5.3"
|
||||
futures-channel = { version = "0.3.4", default-features = false }
|
||||
futures-sink = { version = "0.3.4", default-features = false }
|
||||
futures-util = { version = "0.3.4", default-features = false }
|
||||
pin-project = "0.4.17"
|
||||
log = "0.4"
|
||||
pin-project = "1.0.0"
|
||||
slab = "0.4"
|
||||
|
@@ -7,7 +7,7 @@ use crate::task::LocalWaker;
|
||||
#[derive(Clone)]
|
||||
/// Simple counter with ability to notify task on reaching specific number
|
||||
///
|
||||
/// Counter could be cloned, total ncount is shared across all clones.
|
||||
/// Counter could be cloned, total n-count is shared across all clones.
|
||||
pub struct Counter(Rc<CounterInner>);
|
||||
|
||||
struct CounterInner {
|
||||
|
@@ -1,5 +1,7 @@
|
||||
//! Framed dispatcher service and related utilities
|
||||
|
||||
#![allow(type_alias_bounds)]
|
||||
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::{fmt, mem};
|
@@ -152,7 +152,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_newtransform() {
|
||||
async fn test_new_transform() {
|
||||
let wait_time = Duration::from_millis(50);
|
||||
|
||||
let srv = apply(InFlight::new(1), fn_factory(|| ok(SleepService(wait_time))));
|
||||
|
@@ -1,11 +1,12 @@
|
||||
//! Actix utils - various helper services
|
||||
|
||||
#![deny(rust_2018_idioms)]
|
||||
#![allow(clippy::type_complexity)]
|
||||
|
||||
pub mod condition;
|
||||
pub mod counter;
|
||||
pub mod dispatcher;
|
||||
pub mod either;
|
||||
pub mod framed;
|
||||
pub mod inflight;
|
||||
pub mod keepalive;
|
||||
pub mod mpsc;
|
||||
|
@@ -170,7 +170,7 @@ pub struct PReceiver<T> {
|
||||
inner: Rc<RefCell<Slab<PoolInner<T>>>>,
|
||||
}
|
||||
|
||||
// The oneshots do not ever project Pin to the inner T
|
||||
// The one-shots do not ever project Pin to the inner T
|
||||
impl<T> Unpin for PReceiver<T> {}
|
||||
impl<T> Unpin for PSender<T> {}
|
||||
|
||||
|
@@ -231,7 +231,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_inorder() {
|
||||
async fn test_in_order() {
|
||||
let (tx1, rx1) = oneshot::channel();
|
||||
let (tx2, rx2) = oneshot::channel();
|
||||
let (tx3, rx3) = oneshot::channel();
|
||||
|
@@ -36,7 +36,7 @@ impl LocalWaker {
|
||||
|
||||
#[inline]
|
||||
/// Check if waker has been registered.
|
||||
pub fn is_registed(&self) -> bool {
|
||||
pub fn is_registered(&self) -> bool {
|
||||
unsafe { (*self.waker.get()).is_some() }
|
||||
}
|
||||
|
||||
|
@@ -173,7 +173,7 @@ mod tests {
|
||||
///
|
||||
/// Expected Behavior: Two back-to-back calls of `LowResTimeService::now()` return the same value.
|
||||
#[actix_rt::test]
|
||||
async fn lowres_time_service_time_does_not_immediately_change() {
|
||||
async fn low_res_time_service_time_does_not_immediately_change() {
|
||||
let resolution = Duration::from_millis(50);
|
||||
let time_service = LowResTimeService::with(resolution);
|
||||
assert_eq!(time_service.now(), time_service.now());
|
||||
@@ -210,7 +210,7 @@ mod tests {
|
||||
/// Expected Behavior: Two calls of `LowResTimeService::now()` made in subsequent resolution interval return different values
|
||||
/// and second value is greater than the first one at least by a resolution interval.
|
||||
#[actix_rt::test]
|
||||
async fn lowres_time_service_time_updates_after_resolution_interval() {
|
||||
async fn low_res_time_service_time_updates_after_resolution_interval() {
|
||||
let resolution = Duration::from_millis(100);
|
||||
let wait_time = Duration::from_millis(300);
|
||||
let time_service = LowResTimeService::with(resolution);
|
||||
|
@@ -220,7 +220,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_timeout_newservice() {
|
||||
async fn test_timeout_new_service() {
|
||||
let resolution = Duration::from_millis(100);
|
||||
let wait_time = Duration::from_millis(500);
|
||||
|
||||
|
@@ -1,77 +0,0 @@
|
||||
//! simple composite service
|
||||
//! build: cargo run --example basic --features "ssl"
|
||||
//! to test: curl https://127.0.0.1:8443/ -k
|
||||
use std::sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
Arc,
|
||||
};
|
||||
use std::{env, fmt, io};
|
||||
|
||||
use actix_codec::{AsyncRead, AsyncWrite};
|
||||
use actix_rt::System;
|
||||
use actix_server::{Io, Server};
|
||||
use actix_service::{service_fn, NewService};
|
||||
use futures_util::{future, Future};
|
||||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
|
||||
use tokio_openssl::SslAcceptorExt;
|
||||
|
||||
/// Simple logger service, it just prints fact of the new connections
|
||||
fn logger<T: AsyncRead + AsyncWrite + fmt::Debug>(
|
||||
stream: T,
|
||||
) -> impl Future<Item = T, Error = ()> {
|
||||
println!("New connection: {:?}", stream);
|
||||
future::ok(stream)
|
||||
}
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
env::set_var("RUST_LOG", "actix_net=trace");
|
||||
env_logger::init();
|
||||
|
||||
let sys = System::new("test");
|
||||
|
||||
// load ssl keys
|
||||
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
|
||||
builder
|
||||
.set_private_key_file("./examples/key.pem", SslFiletype::PEM)
|
||||
.unwrap();
|
||||
builder
|
||||
.set_certificate_chain_file("./examples/cert.pem")
|
||||
.unwrap();
|
||||
let acceptor = builder.build();
|
||||
|
||||
let num = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
// bind socket address and start workers. By default server uses number of
|
||||
// available logical cpu as threads count. actix net start separate
|
||||
// instances of service pipeline in each worker.
|
||||
Server::build()
|
||||
.bind(
|
||||
// configure service pipeline
|
||||
"basic",
|
||||
"0.0.0.0:8443",
|
||||
move || {
|
||||
let num = num.clone();
|
||||
let acceptor = acceptor.clone();
|
||||
|
||||
// service for converting incoming TcpStream to a SslStream<TcpStream>
|
||||
service_fn(move |stream: Io<tokio_tcp::TcpStream>| {
|
||||
SslAcceptorExt::accept_async(&acceptor, stream.into_parts().0)
|
||||
.map_err(|e| println!("Openssl error: {}", e))
|
||||
})
|
||||
// .and_then() combinator uses other service to convert incoming `Request` to a
|
||||
// `Response` and then uses that response as an input for next
|
||||
// service. in this case, on success we use `logger` service
|
||||
.and_then(logger)
|
||||
// Next service counts number of connections
|
||||
.and_then(move |_| {
|
||||
let num = num.fetch_add(1, Ordering::Relaxed);
|
||||
println!("got ssl connection {:?}", num);
|
||||
future::ok(())
|
||||
})
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
.start();
|
||||
|
||||
sys.run()
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFPjCCAyYCCQDvLYiYD+jqeTANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJV
|
||||
UzELMAkGA1UECAwCQ0ExCzAJBgNVBAcMAlNGMRAwDgYDVQQKDAdDb21wYW55MQww
|
||||
CgYDVQQLDANPcmcxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xODAxMjUx
|
||||
NzQ2MDFaFw0xOTAxMjUxNzQ2MDFaMGExCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJD
|
||||
QTELMAkGA1UEBwwCU0YxEDAOBgNVBAoMB0NvbXBhbnkxDDAKBgNVBAsMA09yZzEY
|
||||
MBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
|
||||
MIICCgKCAgEA2WzIA2IpVR9Tb9EFhITlxuhE5rY2a3S6qzYNzQVgSFggxXEPn8k1
|
||||
sQEcer5BfAP986Sck3H0FvB4Bt/I8PwOtUCmhwcc8KtB5TcGPR4fjXnrpC+MIK5U
|
||||
NLkwuyBDKziYzTdBj8kUFX1WxmvEHEgqToPOZfBgsS71cJAR/zOWraDLSRM54jXy
|
||||
voLZN4Ti9rQagQrvTQ44Vz5ycDQy7UxtbUGh1CVv69vNVr7/SOOh/Nw5FNOZWLWr
|
||||
odGyoec5wh9iqRZgRqiTUc6Lt7V2RWc2X2gjwST2UfI+U46Ip3oaQ7ZD4eAkoqND
|
||||
xdniBZAykVG3c/99ux4BAESTF8fsNch6UticBxYMuTu+ouvP0psfI9wwwNliJDmA
|
||||
CRUTB9AgRynbL1AzhqQoDfsb98IZfjfNOpwnwuLwpMAPhbgd5KNdZaIJ4Hb6/stI
|
||||
yFElOExxd3TAxF2Gshd/lq1JcNHAZ1DSXV5MvOWT/NWgXwbIzUgQ8eIi+HuDYX2U
|
||||
UuaB6R8tbd52H7rbUv6HrfinuSlKWqjSYLkiKHkwUpoMw8y9UycRSzs1E9nPwPTO
|
||||
vRXb0mNCQeBCV9FvStNVXdCUTT8LGPv87xSD2pmt7LijlE6mHLG8McfcWkzA69un
|
||||
CEHIFAFDimTuN7EBljc119xWFTcHMyoZAfFF+oTqwSbBGImruCxnaJECAwEAATAN
|
||||
BgkqhkiG9w0BAQsFAAOCAgEApavsgsn7SpPHfhDSN5iZs1ILZQRewJg0Bty0xPfk
|
||||
3tynSW6bNH3nSaKbpsdmxxomthNSQgD2heOq1By9YzeOoNR+7Pk3s4FkASnf3ToI
|
||||
JNTUasBFFfaCG96s4Yvs8KiWS/k84yaWuU8c3Wb1jXs5Rv1qE1Uvuwat1DSGXSoD
|
||||
JNluuIkCsC4kWkyq5pWCGQrabWPRTWsHwC3PTcwSRBaFgYLJaR72SloHB1ot02zL
|
||||
d2age9dmFRFLLCBzP+D7RojBvL37qS/HR+rQ4SoQwiVc/JzaeqSe7ZbvEH9sZYEu
|
||||
ALowJzgbwro7oZflwTWunSeSGDSltkqKjvWvZI61pwfHKDahUTmZ5h2y67FuGEaC
|
||||
CIOUI8dSVSPKITxaq3JL4ze2e9/0Lt7hj19YK2uUmtMAW5Tirz4Yx5lyGH9U8Wur
|
||||
y/X8VPxTc4A9TMlJgkyz0hqvhbPOT/zSWB10zXh0glKAsSBryAOEDxV1UygmSir7
|
||||
YV8Qaq+oyKUTMc1MFq5vZ07M51EPaietn85t8V2Y+k/8XYltRp32NxsypxAJuyxh
|
||||
g/ko6RVTrWa1sMvz/F9LFqAdKiK5eM96lh9IU4xiLg4ob8aS/GRAA8oIFkZFhLrt
|
||||
tOwjIUPmEPyHWFi8dLpNuQKYalLYhuwZftG/9xV+wqhKGZO9iPrpHSYBRTap8w2y
|
||||
1QU=
|
||||
-----END CERTIFICATE-----
|
@@ -1,51 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
@@ -1,51 +0,0 @@
|
||||
use std::io;
|
||||
use std::sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
Arc,
|
||||
};
|
||||
|
||||
use actix_rt::System;
|
||||
use actix_server::{ssl, Server};
|
||||
use actix_service::NewService;
|
||||
use futures_util::future;
|
||||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ServiceState {
|
||||
num: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let sys = System::new("test");
|
||||
|
||||
// load ssl keys
|
||||
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
|
||||
builder
|
||||
.set_private_key_file("./examples/key.pem", SslFiletype::PEM)
|
||||
.unwrap();
|
||||
builder
|
||||
.set_certificate_chain_file("./examples/cert.pem")
|
||||
.unwrap();
|
||||
|
||||
let num = Arc::new(AtomicUsize::new(0));
|
||||
let openssl = ssl::OpensslAcceptor::new(builder.build());
|
||||
|
||||
// server start mutiple workers, it runs supplied `Fn` in each worker.
|
||||
Server::build()
|
||||
.bind("test-ssl", "0.0.0.0:8443", move || {
|
||||
let num = num.clone();
|
||||
|
||||
// configure service
|
||||
openssl
|
||||
.clone()
|
||||
.map_err(|e| println!("Openssl error: {}", e))
|
||||
.and_then(move |_| {
|
||||
let num = num.fetch_add(1, Ordering::Relaxed);
|
||||
println!("got ssl connection {:?}", num);
|
||||
future::ok(())
|
||||
})
|
||||
})?
|
||||
.start();
|
||||
|
||||
sys.run()
|
||||
}
|
@@ -1,53 +1,55 @@
|
||||
# Changes
|
||||
|
||||
## [0.2.4] - 2019-12-31
|
||||
## Unreleased - 2020-xx-xx
|
||||
|
||||
|
||||
## 0.2.5 - 2020-09-20
|
||||
* Fix `from_hex()` method
|
||||
|
||||
|
||||
## 0.2.4 - 2019-12-31
|
||||
* Add `ResourceDef::resource_path_named()` path generation method
|
||||
|
||||
## [0.2.3] - 2019-12-25
|
||||
|
||||
## 0.2.3 - 2019-12-25
|
||||
* Add impl `IntoPattern` for `&String`
|
||||
|
||||
## [0.2.2] - 2019-12-25
|
||||
|
||||
## 0.2.2 - 2019-12-25
|
||||
* Use `IntoPattern` for `RouterBuilder::path()`
|
||||
|
||||
## [0.2.1] - 2019-12-25
|
||||
|
||||
## 0.2.1 - 2019-12-25
|
||||
* Add `IntoPattern` trait
|
||||
|
||||
* Add multi-pattern resources
|
||||
|
||||
## [0.2.0] - 2019-12-07
|
||||
|
||||
## 0.2.0 - 2019-12-07
|
||||
* Update http to 0.2
|
||||
|
||||
* Update regex to 1.3
|
||||
|
||||
* Use bytestring instead of string
|
||||
|
||||
## [0.1.5] - 2019-05-15
|
||||
|
||||
## 0.1.5 - 2019-05-15
|
||||
* Remove debug prints
|
||||
|
||||
## [0.1.4] - 2019-05-15
|
||||
|
||||
## 0.1.4 - 2019-05-15
|
||||
* Fix checked resource match
|
||||
|
||||
## [0.1.3] - 2019-04-22
|
||||
|
||||
## 0.1.3 - 2019-04-22
|
||||
* Added support for `remainder match` (i.e "/path/{tail}*")
|
||||
|
||||
## [0.1.2] - 2019-04-07
|
||||
|
||||
## 0.1.2 - 2019-04-07
|
||||
* Export `Quoter` type
|
||||
|
||||
* Allow to reset `Path` instance
|
||||
|
||||
## [0.1.1] - 2019-04-03
|
||||
|
||||
## 0.1.1 - 2019-04-03
|
||||
* Get dynamic segment by name instead of iterator.
|
||||
|
||||
## [0.1.0] - 2019-03-09
|
||||
|
||||
## 0.1.0 - 2019-03-09
|
||||
* Initial release
|
||||
|
@@ -1,8 +1,8 @@
|
||||
[package]
|
||||
name = "actix-router"
|
||||
version = "0.2.4"
|
||||
version = "0.2.5"
|
||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||
description = "Path router"
|
||||
description = "Resource path matching library"
|
||||
keywords = ["actix"]
|
||||
homepage = "https://actix.rs"
|
||||
repository = "https://github.com/actix/actix-net.git"
|
||||
@@ -22,7 +22,7 @@ regex = "1.3.1"
|
||||
serde = "1.0.104"
|
||||
bytestring = "0.1.2"
|
||||
log = "0.4.8"
|
||||
http = { version="0.2.0", optional=true }
|
||||
http = { version = "0.2.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
http = "0.2.0"
|
||||
|
@@ -161,9 +161,7 @@ impl<'de, T: ResourcePath + 'de> Deserializer<'de> for PathDeserializer<'de, T>
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
if self.path.is_empty() {
|
||||
Err(de::value::Error::custom(
|
||||
"expeceted at least one parameters",
|
||||
))
|
||||
Err(de::value::Error::custom("expected at least one parameters"))
|
||||
} else {
|
||||
visitor.visit_enum(ValueEnum {
|
||||
value: &self.path[0],
|
||||
|
@@ -1,4 +1,5 @@
|
||||
//! Resource path matching library.
|
||||
|
||||
mod de;
|
||||
mod path;
|
||||
mod resource;
|
||||
|
@@ -155,7 +155,7 @@ impl ResourceDef {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Check if path matchs this pattern?
|
||||
/// Check if path matches this pattern.
|
||||
pub fn is_match(&self, path: &str) -> bool {
|
||||
match self.tp {
|
||||
PatternType::Static(ref s) => s == path,
|
||||
@@ -165,15 +165,15 @@ impl ResourceDef {
|
||||
}
|
||||
}
|
||||
|
||||
/// Is prefix path a match against this resource?
|
||||
/// Is prefix path a match against this resource.
|
||||
pub fn is_prefix_match(&self, path: &str) -> Option<usize> {
|
||||
let plen = path.len();
|
||||
let p_len = path.len();
|
||||
let path = if path.is_empty() { "/" } else { path };
|
||||
|
||||
match self.tp {
|
||||
PatternType::Static(ref s) => {
|
||||
if s == path {
|
||||
Some(plen)
|
||||
Some(p_len)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -211,7 +211,7 @@ impl ResourceDef {
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
Some(min(plen, len))
|
||||
Some(min(p_len, len))
|
||||
}
|
||||
PatternType::DynamicSet(ref re, ref params) => {
|
||||
if let Some(idx) = re.matches(path).into_iter().next() {
|
||||
@@ -240,7 +240,7 @@ impl ResourceDef {
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the given path and parameters a match against this pattern?
|
||||
/// Is the given path and parameters a match against this pattern.
|
||||
pub fn match_path<T: ResourcePath>(&self, path: &mut Path<T>) -> bool {
|
||||
match self.tp {
|
||||
PatternType::Static(ref s) => {
|
||||
@@ -252,11 +252,11 @@ impl ResourceDef {
|
||||
}
|
||||
}
|
||||
PatternType::Prefix(ref s) => {
|
||||
let rpath = path.path();
|
||||
let len = if s == rpath {
|
||||
let r_path = path.path();
|
||||
let len = if s == r_path {
|
||||
s.len()
|
||||
} else if rpath.starts_with(s)
|
||||
&& (s.ends_with('/') || rpath.split_at(s.len()).1.starts_with('/'))
|
||||
} else if r_path.starts_with(s)
|
||||
&& (s.ends_with('/') || r_path.split_at(s.len()).1.starts_with('/'))
|
||||
{
|
||||
if s.ends_with('/') {
|
||||
s.len() - 1
|
||||
@@ -266,8 +266,8 @@ impl ResourceDef {
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
let rpath_len = rpath.len();
|
||||
path.skip(min(rpath_len, len) as u16);
|
||||
let r_path_len = r_path.len();
|
||||
path.skip(min(r_path_len, len) as u16);
|
||||
true
|
||||
}
|
||||
PatternType::Dynamic(ref re, ref names, len) => {
|
||||
@@ -361,11 +361,11 @@ impl ResourceDef {
|
||||
}
|
||||
PatternType::Prefix(ref s) => {
|
||||
let len = {
|
||||
let rpath = res.resource_path().path();
|
||||
if s == rpath {
|
||||
let r_path = res.resource_path().path();
|
||||
if s == r_path {
|
||||
s.len()
|
||||
} else if rpath.starts_with(s)
|
||||
&& (s.ends_with('/') || rpath.split_at(s.len()).1.starts_with('/'))
|
||||
} else if r_path.starts_with(s)
|
||||
&& (s.ends_with('/') || r_path.split_at(s.len()).1.starts_with('/'))
|
||||
{
|
||||
if s.ends_with('/') {
|
||||
s.len() - 1
|
||||
@@ -580,6 +580,8 @@ impl ResourceDef {
|
||||
mut for_prefix: bool,
|
||||
) -> (String, Vec<PatternElement>, bool, usize) {
|
||||
if pattern.find('{').is_none() {
|
||||
// TODO: MSRV: 1.45
|
||||
#[allow(clippy::manual_strip)]
|
||||
return if pattern.ends_with('*') {
|
||||
let path = &pattern[..pattern.len() - 1];
|
||||
let re = String::from("^") + path + "(.*)";
|
||||
@@ -594,39 +596,39 @@ impl ResourceDef {
|
||||
};
|
||||
}
|
||||
|
||||
let mut elems = Vec::new();
|
||||
let mut elements = Vec::new();
|
||||
let mut re = String::from("^");
|
||||
let mut dyn_elems = 0;
|
||||
let mut dyn_elements = 0;
|
||||
|
||||
while let Some(idx) = pattern.find('{') {
|
||||
let (prefix, rem) = pattern.split_at(idx);
|
||||
elems.push(PatternElement::Str(String::from(prefix)));
|
||||
elements.push(PatternElement::Str(String::from(prefix)));
|
||||
re.push_str(&escape(prefix));
|
||||
let (param_pattern, re_part, rem, tail) = Self::parse_param(rem);
|
||||
if tail {
|
||||
for_prefix = true;
|
||||
}
|
||||
|
||||
elems.push(param_pattern);
|
||||
elements.push(param_pattern);
|
||||
re.push_str(&re_part);
|
||||
pattern = rem;
|
||||
dyn_elems += 1;
|
||||
dyn_elements += 1;
|
||||
}
|
||||
|
||||
elems.push(PatternElement::Str(String::from(pattern)));
|
||||
elements.push(PatternElement::Str(String::from(pattern)));
|
||||
re.push_str(&escape(pattern));
|
||||
|
||||
if dyn_elems > MAX_DYNAMIC_SEGMENTS {
|
||||
if dyn_elements > MAX_DYNAMIC_SEGMENTS {
|
||||
panic!(
|
||||
"Only {} dynanic segments are allowed, provided: {}",
|
||||
MAX_DYNAMIC_SEGMENTS, dyn_elems
|
||||
"Only {} dynamic segments are allowed, provided: {}",
|
||||
MAX_DYNAMIC_SEGMENTS, dyn_elements
|
||||
);
|
||||
}
|
||||
|
||||
if !for_prefix {
|
||||
re.push_str("$");
|
||||
re.push('$');
|
||||
}
|
||||
(re, elems, true, pattern.chars().count())
|
||||
(re, elements, true, pattern.chars().count())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -718,10 +720,10 @@ mod tests {
|
||||
assert!(!re.is_match("/v/resource/1"));
|
||||
assert!(!re.is_match("/resource"));
|
||||
|
||||
let mut path = Path::new("/v151/resource/adahg32");
|
||||
let mut path = Path::new("/v151/resource/adage32");
|
||||
assert!(re.match_path(&mut path));
|
||||
assert_eq!(path.get("version").unwrap(), "151");
|
||||
assert_eq!(path.get("id").unwrap(), "adahg32");
|
||||
assert_eq!(path.get("id").unwrap(), "adage32");
|
||||
|
||||
let re = ResourceDef::new("/{id:[[:digit:]]{6}}");
|
||||
assert!(re.is_match("/012345"));
|
||||
@@ -759,10 +761,10 @@ mod tests {
|
||||
assert!(!re.is_match("/v/resource/1"));
|
||||
assert!(!re.is_match("/resource"));
|
||||
|
||||
let mut path = Path::new("/v151/resource/adahg32");
|
||||
let mut path = Path::new("/v151/resource/adage32");
|
||||
assert!(re.match_path(&mut path));
|
||||
assert_eq!(path.get("version").unwrap(), "151");
|
||||
assert_eq!(path.get("id").unwrap(), "adahg32");
|
||||
assert_eq!(path.get("id").unwrap(), "adage32");
|
||||
|
||||
assert!(re.is_match("/012345"));
|
||||
assert!(!re.is_match("/012"));
|
||||
@@ -875,7 +877,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reousrce_prefix_dynamic() {
|
||||
fn test_resource_prefix_dynamic() {
|
||||
let re = ResourceDef::prefix("/{name}/");
|
||||
assert!(re.is_match("/name/"));
|
||||
assert!(re.is_match("/name/gs"));
|
||||
|
@@ -182,11 +182,11 @@ impl Quoter {
|
||||
|
||||
#[inline]
|
||||
fn from_hex(v: u8) -> Option<u8> {
|
||||
if v >= b'0' && v <= b'9' {
|
||||
if (b'0'..=b'9').contains(&v) {
|
||||
Some(v - 0x30) // ord('0') == 0x30
|
||||
} else if v >= b'A' && v <= b'F' {
|
||||
} else if (b'A'..=b'F').contains(&v) {
|
||||
Some(v - 0x41 + 10) // ord('A') == 0x41
|
||||
} else if v > b'a' && v <= b'f' {
|
||||
} else if (b'a'..=b'f').contains(&v) {
|
||||
Some(v - 0x61 + 10) // ord('a') == 0x61
|
||||
} else {
|
||||
None
|
||||
@@ -225,4 +225,25 @@ mod tests {
|
||||
assert!(re.match_path(&mut path));
|
||||
assert_eq!(path.get("id").unwrap(), "qwe%rty");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_hex() {
|
||||
let hex = b"0123456789abcdefABCDEF";
|
||||
|
||||
for i in 0..256 {
|
||||
let c = i as u8;
|
||||
if hex.contains(&c) {
|
||||
assert!(from_hex(c).is_some())
|
||||
} else {
|
||||
assert!(from_hex(c).is_none())
|
||||
}
|
||||
}
|
||||
|
||||
let expected = [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 10, 11, 12, 13, 14, 15,
|
||||
];
|
||||
for i in 0..hex.len() {
|
||||
assert_eq!(from_hex(hex[i]).unwrap(), expected[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user