1
0
mirror of https://github.com/fafhrd91/actix-net synced 2025-08-12 09:57:07 +02:00

Compare commits

..

48 Commits

Author SHA1 Message Date
Rob Ede
49a034259f prepare local-waker release 0.1.3 2022-05-03 14:58:09 +01:00
Rob Ede
3337f63b4e prepare local-channel release 0.1.3 2022-05-03 14:56:40 +01:00
Rob Ede
86ce140249 ensure all crates include license files
closes #456
2022-05-03 14:55:49 +01:00
Guillaume Desmottes
635aebe887 actix-server: fix UNIX signal handling documentation (#455) 2022-05-03 13:37:18 +01:00
Rob Ede
4c1e581a54 add track_caller atrtibute to spawn calls (#454)
* add track_caller attribute to spawn calls

* fix ci
2022-04-25 21:05:48 +01:00
Rob Ede
dc67ba770d fmt with import grouping 2022-04-10 02:48:53 +01:00
Rob Ede
855e3f96fe prepare actix-tls release 3.0.4 2022-03-15 19:43:47 +00:00
Rob Ede
737b438f73 prepare actix-codec release 0.5.1 2022-03-15 19:43:06 +00:00
Rob Ede
0cd70b0536 use tracing for logs (#451) 2022-03-15 19:37:08 +00:00
Rob Ede
4b6a581ef3 prepare actix-server release 2.1.1 2022-03-09 01:08:35 +00:00
Rob Ede
3e132d2bc6 update tokio-uring to 0.3 (#448) 2022-03-08 23:42:52 +00:00
Rob Ede
c5d6174cec add tracing support 2022-03-08 22:13:55 +00:00
Rob Ede
77d4a69b2f update tokio-uring to 0.3 (#449) 2022-03-08 21:57:02 +00:00
Rob Ede
ae5377fd6e update readme 2022-03-08 21:12:46 +00:00
Rob Ede
bd9bda0504 fix readme msrv notes 2022-03-02 16:42:53 +00:00
Rob Ede
41ed48219d bump lower msrv to 1.49 2022-03-02 16:40:11 +00:00
fakeshadow
7804ed12eb block and wait for accept thread to exit. (#443)
Co-authored-by: Rob Ede <robjtede@icloud.com>
2022-03-02 03:52:12 +00:00
Rob Ede
2a54065fae parallel master tests using nextest 2022-02-15 14:19:00 +00:00
Rob Ede
217cbd2228 bump tokio-util to 0.7 (#446) 2022-02-15 01:47:27 +00:00
Rob Ede
d229c1e886 fix min ver check 2022-02-12 08:42:13 +00:00
Rob Ede
6792f799a6 add minimal-versions check 2022-02-12 08:37:56 +00:00
Rob Ede
72481313cc update readme 2022-01-28 22:28:24 +00:00
Rob Ede
59b629c74b fix deps badge 2022-01-28 22:17:12 +00:00
Rob Ede
7988694242 update msrv info 2022-01-28 22:15:16 +00:00
Rob Ede
b8a7741524 fix bind_addr 2022-01-28 22:13:10 +00:00
Rob Ede
5e290d76f8 prepare actix-tls release 3.0.2 2022-01-28 22:11:21 +00:00
Rob Ede
0edb64575f update tls changelog 2022-01-28 22:10:24 +00:00
Rob Ede
941f67dec9 s/e/err 2022-01-28 22:10:06 +00:00
Babur
3e624b8376 Made new constructor for the Connection type public (#439) 2022-01-28 22:09:54 +00:00
Ibraheem Ahmed
26446fdbad Replace derive_more with declarative macros (#438)
Co-authored-by: Rob Ede <robjtede@icloud.com>
2022-01-28 22:09:33 +00:00
Rob Ede
b7b7bd2cbf add actix-server readme 2022-01-19 16:14:06 +00:00
Rob Ede
637625f9b7 prepare actix-server release 2.0.0 (#437) 2022-01-19 14:57:50 +00:00
Rob Ede
b1d5d85e72 prepare actix-server release 2.0.0-rc.4 2022-01-12 14:40:06 +00:00
Rob Ede
ed2c07b304 prepare actix-rt release 2.6.0 2022-01-12 14:40:06 +00:00
Rob Ede
4fe7fec5ef update tokio-uring to 0.2.0 (#436) 2022-01-11 23:36:49 +00:00
Rob Ede
4c9ee88ec4 prepare actix-tls release 3.0.1 2022-01-11 22:17:31 +00:00
david-mcgillicuddy-moixa
9ec3cc0fe7 Replace str_split_once to lower actix-tls msrv to 1.50.0 and bump actix-net to 1.50.0 (#434) 2022-01-10 17:00:04 +00:00
Rob Ede
01e0f922de fix ci 2021-12-31 08:38:37 +00:00
Rob Ede
10d3bb6d0d only run coverage on master ci 2021-12-31 08:36:13 +00:00
Rob Ede
3ba4eafde5 prepare actix-server release 2.0.0-rc.3 2021-12-31 08:09:28 +00:00
Rob Ede
5faa98f6d2 prepare actix-rt release 2.5.1 2021-12-31 08:09:10 +00:00
Rob Ede
b552d847ed prepare actix-codec release 0.4.2 2021-12-31 08:08:14 +00:00
Rob Ede
5058e2d14e bump tokio in local-channel dev deps 2021-12-31 08:06:41 +00:00
Rob Ede
ae9afd4de7 prepare actix-server release 2.0.0-rc.2 2021-12-27 18:33:57 +00:00
Rob Ede
01d2f18f68 simplify test server (#431) 2021-12-27 18:27:54 +00:00
Rob Ede
e92b5aaf31 expose with_tokio_rt (#430) 2021-12-27 16:00:26 +00:00
Rob Ede
459a6d1b02 update readme 2021-12-27 00:57:16 +00:00
Rob Ede
9935883905 add file reader example 2021-12-26 22:32:35 +00:00
75 changed files with 958 additions and 365 deletions

213
.github/workflows/ci-master.yml vendored Normal file
View File

@@ -0,0 +1,213 @@
name: CI (master only)
on:
push:
branches: [master]
jobs:
build_and_test_nightly:
strategy:
fail-fast: false
matrix:
target:
- { name: Linux, os: ubuntu-latest, triple: x86_64-unknown-linux-gnu }
- { name: macOS, os: macos-latest, triple: x86_64-apple-darwin }
- { name: Windows, os: windows-latest, triple: x86_64-pc-windows-msvc }
- { name: Windows (MinGW), os: windows-latest, triple: x86_64-pc-windows-gnu }
- { name: Windows (32-bit), os: windows-latest, triple: i686-pc-windows-msvc }
version:
- nightly
name: ${{ matrix.target.name }} / ${{ matrix.version }}
runs-on: ${{ matrix.target.os }}
env:
VCPKGRS_DYNAMIC: 1
steps:
- name: Setup Routing
if: matrix.target.os == 'macos-latest'
run: sudo ifconfig lo0 alias 127.0.0.3
- uses: actions/checkout@v2
# install OpenSSL on Windows
- name: Set vcpkg root
if: matrix.target.triple == 'x86_64-pc-windows-msvc' || matrix.target.triple == 'i686-pc-windows-msvc'
run: echo "VCPKG_ROOT=$env:VCPKG_INSTALLATION_ROOT" | Out-File -FilePath $env:GITHUB_ENV -Append
- name: Install OpenSSL
if: matrix.target.triple == 'x86_64-pc-windows-msvc'
run: vcpkg install openssl:x64-windows
- name: Install OpenSSL
if: matrix.target.triple == 'i686-pc-windows-msvc'
run: vcpkg install openssl:x86-windows
- name: Install ${{ matrix.version }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.version }}-${{ matrix.target.triple }}
profile: minimal
override: true
# - name: Install MSYS2
# if: matrix.target.triple == 'x86_64-pc-windows-gnu'
# uses: msys2/setup-msys2@v2
# - name: Install MinGW Packages
# if: matrix.target.triple == 'x86_64-pc-windows-gnu'
# run: |
# msys2 -c 'pacman -Sy --noconfirm pacman'
# msys2 -c 'pacman --noconfirm -S base-devel pkg-config'
# - name: Generate Cargo.lock
# uses: actions-rs/cargo@v1
# with: { command: generate-lockfile }
# - name: Cache Dependencies
# uses: Swatinem/rust-cache@v1.2.0
- name: Install cargo-hack
uses: actions-rs/cargo@v1
with:
command: install
args: cargo-hack
- name: check lib
if: >
matrix.target.os != 'ubuntu-latest'
&& matrix.target.triple != 'x86_64-pc-windows-gnu'
uses: actions-rs/cargo@v1
with: { command: ci-check-lib }
- name: check lib
if: matrix.target.os == 'ubuntu-latest'
uses: actions-rs/cargo@v1
with: { command: ci-check-lib-linux }
- name: check lib
if: matrix.target.triple == 'x86_64-pc-windows-gnu'
uses: actions-rs/cargo@v1
with: { command: ci-check-min }
- name: check full
# TODO: compile OpenSSL and run tests on MinGW
if: >
matrix.target.os != 'ubuntu-latest'
&& matrix.target.triple != 'x86_64-pc-windows-gnu'
uses: actions-rs/cargo@v1
with: { command: ci-check }
- name: check all
if: matrix.target.os == 'ubuntu-latest'
uses: actions-rs/cargo@v1
with: { command: ci-check-linux }
- name: tests
if: >
matrix.target.os != 'ubuntu-latest'
&& matrix.target.triple != 'x86_64-pc-windows-gnu'
run: |
cargo ci-test
cargo ci-test-rt
cargo ci-test-server
- name: tests
if: matrix.target.os == 'ubuntu-latest'
run: |
sudo bash -c "ulimit -Sl 512 && ulimit -Hl 512 && PATH=$PATH:/usr/share/rust/.cargo/bin && RUSTUP_TOOLCHAIN=${{ matrix.version }} cargo ci-test && RUSTUP_TOOLCHAIN=${{ matrix.version }} cargo ci-test-rt-linux && RUSTUP_TOOLCHAIN=${{ matrix.version }} cargo ci-test-server-linux"
- name: Clear the cargo caches
run: |
cargo install cargo-cache --version 0.6.2 --no-default-features --features ci-autoclean
cargo-cache
coverage:
name: coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust (nightly)
uses: actions-rs/toolchain@v1
with:
toolchain: nightly
profile: minimal
override: true
- name: Generate Cargo.lock
uses: actions-rs/cargo@v1
with: { command: generate-lockfile }
- name: Cache Dependencies
uses: Swatinem/rust-cache@v1.3.0
- name: Generate coverage file
if: github.ref == 'refs/heads/master'
run: |
cargo install cargo-tarpaulin
cargo tarpaulin --out Xml --verbose
- name: Upload to Codecov
if: github.ref == 'refs/heads/master'
uses: codecov/codecov-action@v1
with: { file: cobertura.xml }
minimal-versions:
name: minimal versions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust (nightly)
uses: actions-rs/toolchain@v1
with:
toolchain: nightly
profile: minimal
override: true
- name: Generate Cargo.lock
uses: actions-rs/cargo@v1
with: { command: generate-lockfile }
- name: Cache Dependencies
uses: Swatinem/rust-cache@v1.3.0
- name: Install cargo-minimal-versions
uses: actions-rs/cargo@v1
with:
command: install
args: cargo-minimal-versions
- name: Install cargo-hack
uses: actions-rs/cargo@v1
with:
command: install
args: cargo-hack
- name: Check With Minimal Versions
uses: actions-rs/cargo@v1
with:
command: minimal-versions
args: check
nextest:
name: nextest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
- name: Generate Cargo.lock
uses: actions-rs/cargo@v1
with: { command: generate-lockfile }
- name: Cache Dependencies
uses: Swatinem/rust-cache@v1.3.0
- name: Install cargo-nextest
uses: actions-rs/cargo@v1
with:
command: install
args: cargo-nextest
- name: Test with cargo-nextest
uses: actions-rs/cargo@v1
with:
command: nextest
args: run

View File

@@ -20,7 +20,6 @@ jobs:
version:
- 1.52.0 # MSRV for -server and -tls
- stable
- nightly
name: ${{ matrix.target.name }} / ${{ matrix.version }}
runs-on: ${{ matrix.target.os }}
@@ -74,6 +73,14 @@ jobs:
command: install
args: cargo-hack
- name: Generate Cargo.lock
uses: actions-rs/cargo@v1
with: { command: generate-lockfile }
- name: Tweak lockfile
run: |
cargo update -p=native-tls --precise=0.2.8
- name: check lib
if: >
matrix.target.os != 'ubuntu-latest'
@@ -88,7 +95,7 @@ jobs:
if: matrix.target.triple == 'x86_64-pc-windows-gnu'
uses: actions-rs/cargo@v1
with: { command: ci-check-min }
- name: check full
# TODO: compile OpenSSL and run tests on MinGW
if: >
@@ -118,17 +125,17 @@ jobs:
run: |
cargo install cargo-cache --version 0.6.2 --no-default-features --features ci-autoclean
cargo-cache
build_and_test_lower_msrv:
name: Linux / 1.46 (lower MSRV)
name: Linux / 1.49 (lower MSRV)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install 1.46.0 # MSRV for all but -server and -tls
- name: Install 1.49.0 # MSRV for all but -server and -tls
uses: actions-rs/toolchain@v1
with:
toolchain: 1.46.0-x86_64-unknown-linux-gnu
toolchain: 1.49.0-x86_64-unknown-linux-gnu
profile: minimal
override: true
@@ -138,43 +145,23 @@ jobs:
command: install
args: cargo-hack
- name: Generate Cargo.lock
uses: actions-rs/cargo@v1
with: { command: generate-lockfile }
- name: Tweak lockfile
run: |
cargo update -p=rustls --precise=0.20.2
cargo update -p=native-tls --precise=0.2.8
- name: tests
run: |
sudo bash -c "ulimit -Sl 512 && ulimit -Hl 512 && PATH=$PATH:/usr/share/rust/.cargo/bin && RUSTUP_TOOLCHAIN=1.46 cargo ci-test-lower-msrv"
sudo bash -c "ulimit -Sl 512 && ulimit -Hl 512 && PATH=$PATH:/usr/share/rust/.cargo/bin && RUSTUP_TOOLCHAIN=1.49 cargo ci-test-lower-msrv"
- name: Clear the cargo caches
run: |
cargo install cargo-cache --version 0.6.2 --no-default-features --features ci-autoclean
cargo-cache
coverage:
name: coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust (nightly)
uses: actions-rs/toolchain@v1
with:
toolchain: stable-x86_64-unknown-linux-gnu
profile: minimal
override: true
- name: Generate Cargo.lock
uses: actions-rs/cargo@v1
with: { command: generate-lockfile }
- name: Cache Dependencies
uses: Swatinem/rust-cache@v1.3.0
- name: Generate coverage file
if: github.ref == 'refs/heads/master'
run: |
cargo install cargo-tarpaulin
cargo tarpaulin --out Xml --verbose
- name: Upload to Codecov
if: github.ref == 'refs/heads/master'
uses: codecov/codecov-action@v1
with: { file: cobertura.xml }
rustdoc:
name: rustdoc

View File

@@ -2,29 +2,25 @@
> A collection of lower-level libraries for composable network services.
![Apache 2.0 or MIT licensed](https://img.shields.io/crates/l/actix-server)
[![CI](https://github.com/actix/actix-net/actions/workflows/ci.yml/badge.svg?event=push&style=flat-square)](https://github.com/actix/actix-net/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/actix/actix-net/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-net)
[![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/NWpN5mmg3x)
[![Dependency Status](https://deps.rs/repo/github/actix/actix-net/status.svg)](https://deps.rs/repo/github/actix/actix-net)
## Build statuses
| Platform | Build Status |
| ---------------- | ------------ |
| Linux | [![build status](https://github.com/actix/actix-net/workflows/CI%20%28Linux%29/badge.svg?branch=master&event=push)](https://github.com/actix/actix-net/actions?query=workflow%3A"CI+(Linux)") |
| macOS | [![build status](https://github.com/actix/actix-net/workflows/CI%20%28macOS%29/badge.svg?branch=master&event=push)](https://github.com/actix/actix-net/actions?query=workflow%3A"CI+(macOS)") |
| Windows | [![build status](https://github.com/actix/actix-net/workflows/CI%20%28Windows%29/badge.svg?branch=master&event=push)](https://github.com/actix/actix-net/actions?query=workflow%3A"CI+(Windows)") |
| Windows (MinGW) | [![build status](https://github.com/actix/actix-net/workflows/CI%20%28Windows-mingw%29/badge.svg?branch=master&event=push)](https://github.com/actix/actix-net/actions?query=workflow%3A"CI+(Windows-mingw)") |
## Examples
## Example
See `actix-server/examples` and `actix-tls/examples` for some basic examples.
See example folders for [`actix-server`](./actix-server/examples) and [`actix-tls`](./actix-tls/examples).
### MSRV
This repo's Minimum Supported Rust Version (MSRV) is 1.46.0.
## MSRV
Most crates in this repo's have a Minimum Supported Rust Version (MSRV) of 1.49.0. Only `actix-tls` and `actix-server` have MSRV of 1.54.0. As a policy, we permit MSRV increases in non-breaking releases.
## License
This project is licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0))
* MIT license ([LICENSE-MIT](LICENSE-MIT) or [http://opensource.org/licenses/MIT](http://opensource.org/licenses/MIT))
The crates in repo are licensed under either of:
- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0))
- MIT license ([LICENSE-MIT](LICENSE-MIT) or [http://opensource.org/licenses/MIT](http://opensource.org/licenses/MIT))
at your option.

View File

@@ -1,6 +1,23 @@
# Changes
## Unreleased - 2021-xx-xx
## Unreleased - 2022-xx-xx
## 0.5.1 - 2022-03-15
- Logs emitted now use the `tracing` crate with `log` compatibility. [#451]
- Minimum supported Rust version (MSRV) is now 1.49.
[#451]: https://github.com/actix/actix-net/pull/451
## 0.5.0 - 2022-02-15
- Updated `tokio-util` dependency to `0.7.0`. [#446]
[#446]: https://github.com/actix/actix-net/pull/446
## 0.4.2 - 2021-12-31
- No significant changes since `0.4.1`.
## 0.4.1 - 2021-11-05

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-codec"
version = "0.4.1"
version = "0.5.1"
authors = [
"Nikolay Kim <fafhrd91@gmail.com>",
"Rob Ede <robjtede@icloud.com>",
@@ -17,15 +17,15 @@ name = "actix_codec"
path = "src/lib.rs"
[dependencies]
bitflags = "1.2.1"
bitflags = "1.2"
bytes = "1"
futures-core = { version = "0.3.7", default-features = false }
futures-sink = { version = "0.3.7", default-features = false }
log = "0.4"
memchr = "2.3"
pin-project-lite = "0.2"
tokio = "1.5.1"
tokio-util = { version = "0.6", features = ["codec", "io"] }
tokio = "1.13.1"
tokio-util = { version = "0.7", features = ["codec", "io"] }
tracing = { version = "0.1.30", default-features = false, features = ["log"] }
[dev-dependencies]
criterion = { version = "0.3", features = ["html_reports"] }

View File

@@ -156,7 +156,7 @@ impl<T, U> Framed<T, U> {
}
impl<T, U> Framed<T, U> {
/// Serialize item and Write to the inner buffer
/// Serialize item and write to the inner buffer
pub fn write<I>(mut self: Pin<&mut Self>, item: I) -> Result<(), <U as Encoder<I>>::Error>
where
T: AsyncWrite,
@@ -193,18 +193,18 @@ impl<T, U> Framed<T, U> {
match this.codec.decode_eof(this.read_buf) {
Ok(Some(frame)) => return Poll::Ready(Some(Ok(frame))),
Ok(None) => return Poll::Ready(None),
Err(e) => return Poll::Ready(Some(Err(e))),
Err(err) => return Poll::Ready(Some(Err(err))),
}
}
log::trace!("attempting to decode a frame");
tracing::trace!("attempting to decode a frame");
match this.codec.decode(this.read_buf) {
Ok(Some(frame)) => {
log::trace!("frame decoded from buffer");
tracing::trace!("frame decoded from buffer");
return Poll::Ready(Some(Ok(frame)));
}
Err(e) => return Poll::Ready(Some(Err(e))),
Err(err) => return Poll::Ready(Some(Err(err))),
_ => (), // Need more data
}
@@ -221,7 +221,7 @@ impl<T, U> Framed<T, U> {
let cnt = match tokio_util::io::poll_read_buf(this.io, cx, this.read_buf) {
Poll::Pending => return Poll::Pending,
Poll::Ready(Err(e)) => return Poll::Ready(Some(Err(e.into()))),
Poll::Ready(Err(err)) => return Poll::Ready(Some(Err(err.into()))),
Poll::Ready(Ok(cnt)) => cnt,
};
@@ -242,10 +242,10 @@ impl<T, U> Framed<T, U> {
U: Encoder<I>,
{
let mut this = self.as_mut().project();
log::trace!("flushing framed transport");
tracing::trace!("flushing framed transport");
while !this.write_buf.is_empty() {
log::trace!("writing; remaining={}", this.write_buf.len());
tracing::trace!("writing; remaining={}", this.write_buf.len());
let n = ready!(this.io.as_mut().poll_write(cx, this.write_buf))?;
@@ -264,7 +264,7 @@ impl<T, U> Framed<T, U> {
// Try flushing the underlying IO
ready!(this.io.poll_flush(cx))?;
log::trace!("framed transport flushed");
tracing::trace!("framed transport flushed");
Poll::Ready(Ok(()))
}

View File

@@ -16,10 +16,10 @@ mod bcodec;
mod framed;
mod lines;
pub use self::bcodec::BytesCodec;
pub use self::framed::{Framed, FramedParts};
pub use self::lines::LinesCodec;
pub use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
pub use tokio_util::codec::{Decoder, Encoder};
pub use tokio_util::io::poll_read_buf;
pub use self::bcodec::BytesCodec;
pub use self::framed::{Framed, FramedParts};
pub use self::lines::LinesCodec;

View File

@@ -7,8 +7,8 @@ use super::{Decoder, Encoder};
/// Lines codec. Reads/writes line delimited strings.
///
/// Will split input up by LF or CRLF delimiters. I.e. carriage return characters at the end of
/// lines are not preserved.
/// Will split input up by LF or CRLF delimiters. Carriage return characters at the end of lines are
/// not preserved.
#[derive(Debug, Copy, Clone, Default)]
#[non_exhaustive]
pub struct LinesCodec;

View File

@@ -1,12 +1,16 @@
use std::{
collections::VecDeque,
io::{self, Write},
pin::Pin,
task::{
Context,
Poll::{self, Pending, Ready},
},
};
use actix_codec::*;
use bytes::Buf;
use bytes::{BufMut, BytesMut};
use bytes::{Buf as _, BufMut as _, BytesMut};
use futures_sink::Sink;
use std::collections::VecDeque;
use std::io::{self, Write};
use std::pin::Pin;
use std::task::Poll::{Pending, Ready};
use std::task::{Context, Poll};
use tokio_test::{assert_ready, task};
macro_rules! bilateral {
@@ -50,7 +54,7 @@ impl Write for Bilateral {
assert_eq!(&data[..], &src[..data.len()]);
Ok(data.len())
}
Some(Err(e)) => Err(e),
Some(Err(err)) => Err(err),
None => panic!("unexpected write; {:?}", src),
}
}
@@ -67,13 +71,13 @@ impl AsyncWrite for Bilateral {
buf: &[u8],
) -> Poll<Result<usize, io::Error>> {
match Pin::get_mut(self).write(buf) {
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Pending,
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => Pending,
other => Ready(other),
}
}
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
match Pin::get_mut(self).flush() {
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Pending,
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => Pending,
other => Ready(other),
}
}
@@ -99,8 +103,8 @@ impl AsyncRead for Bilateral {
buf.put_slice(&data);
Ready(Ok(()))
}
Some(Err(ref e)) if e.kind() == WouldBlock => Pending,
Some(Err(e)) => Ready(Err(e)),
Some(Err(ref err)) if err.kind() == WouldBlock => Pending,
Some(Err(err)) => Ready(Err(err)),
None => Ready(Ok(())),
}
}

View File

@@ -1,6 +1,7 @@
# Changes
## Unreleased - 2021-xx-xx
## Unreleased - 2022-xx-xx
- Minimum supported Rust version (MSRV) is now 1.49.
## 0.2.3 - 2021-10-19

View File

@@ -1,6 +1,28 @@
# Changes
## Unreleased - 2021-xx-xx
## Unreleased - 2022-xx-xx
- Add `#[track_caller]` attribute to `spawn` functions and methods. [#454]
[#454]: https://github.com/actix/actix-net/pull/454
## 2.7.0 - 2022-03-08
- Update `tokio-uring` dependency to `0.3.0`. [#448]
- Minimum supported Rust version (MSRV) is now 1.49.
[#448]: https://github.com/actix/actix-net/pull/448
## 2.6.0 - 2022-01-12
- Update `tokio-uring` dependency to `0.2.0`. [#436]
[#436]: https://github.com/actix/actix-net/pull/436
## 2.5.1 - 2021-12-31
- Expose `System::with_tokio_rt` and `Arbiter::with_tokio_rt`. [#430]
[#430]: https://github.com/actix/actix-net/pull/430
## 2.5.0 - 2021-11-22

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-rt"
version = "2.5.0"
version = "2.7.0"
authors = [
"Nikolay Kim <fafhrd91@gmail.com>",
"Rob Ede <robjtede@icloud.com>",
@@ -27,11 +27,12 @@ io-uring = ["tokio-uring"]
actix-macros = { version = "0.2.3", optional = true }
futures-core = { version = "0.3", default-features = false }
tokio = { version = "1.5.1", features = ["rt", "net", "parking_lot", "signal", "sync", "time"] }
tokio = { version = "1.13.1", features = ["rt", "net", "parking_lot", "signal", "sync", "time"] }
# runtime for `io-uring` feature
[target.'cfg(target_os = "linux")'.dependencies]
tokio-uring = { version = "0.1", optional = true }
tokio-uring = { version = "0.3", optional = true }
[dev-dependencies]
tokio = { version = "1.5.1", features = ["full"] }
hyper = { version = "0.14", default-features = false, features = ["server", "tcp", "http1"] }
tokio = { version = "1.13.1", features = ["full"] }
hyper = { version = "0.14.10", default-features = false, features = ["server", "tcp", "http1"] }

View File

@@ -3,11 +3,11 @@
> Tokio-based single-threaded async runtime for the Actix ecosystem.
[![crates.io](https://img.shields.io/crates/v/actix-rt?label=latest)](https://crates.io/crates/actix-rt)
[![Documentation](https://docs.rs/actix-rt/badge.svg?version=2.5.0)](https://docs.rs/actix-rt/2.5.0)
[![Documentation](https://docs.rs/actix-rt/badge.svg?version=2.7.0)](https://docs.rs/actix-rt/2.7.0)
[![Version](https://img.shields.io/badge/rustc-1.46+-ab6000.svg)](https://blog.rust-lang.org/2020/03/12/Rust-1.46.html)
![MIT or Apache 2.0 licensed](https://img.shields.io/crates/l/actix-rt.svg)
<br />
[![dependency status](https://deps.rs/crate/actix-rt/2.5.0/status.svg)](https://deps.rs/crate/actix-rt/2.5.0)
[![dependency status](https://deps.rs/crate/actix-rt/2.7.0/status.svg)](https://deps.rs/crate/actix-rt/2.7.0)
![Download](https://img.shields.io/crates/d/actix-rt.svg)
[![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/WghFtEH6Hb)

View File

@@ -1,7 +1,9 @@
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server};
use std::convert::Infallible;
use std::net::SocketAddr;
use std::{convert::Infallible, net::SocketAddr};
use hyper::{
service::{make_service_fn, service_fn},
Body, Request, Response, Server,
};
async fn handle(_req: Request<Body>) -> Result<Response<Body>, Infallible> {
Ok(Response::new(Body::from("Hello World")))
@@ -21,8 +23,8 @@ fn main() {
let server =
Server::bind(&SocketAddr::from(([127, 0, 0, 1], 3000))).serve(make_service);
if let Err(e) = server.await {
eprintln!("server error: {}", e);
if let Err(err) = server.await {
eprintln!("server error: {}", err);
}
})
}

View File

@@ -108,7 +108,6 @@ impl Arbiter {
///
/// [tokio-runtime]: tokio::runtime::Runtime
#[cfg(not(all(target_os = "linux", feature = "io-uring")))]
#[doc(hidden)]
pub fn with_tokio_rt<F>(runtime_factory: F) -> Arbiter
where
F: Fn() -> tokio::runtime::Runtime + Send + 'static,
@@ -261,6 +260,7 @@ impl Arbiter {
/// If you require a result, include a response channel in the future.
///
/// Returns true if future was sent successfully and false if the Arbiter has died.
#[track_caller]
pub fn spawn<Fut>(&self, future: Fut) -> bool
where
Fut: Future<Output = ()> + Send + 'static,
@@ -276,6 +276,7 @@ impl Arbiter {
/// channel in the function.
///
/// Returns true if function was sent successfully and false if the Arbiter has died.
#[track_caller]
pub fn spawn_fn<F>(&self, f: F) -> bool
where
F: FnOnce() + Send + 'static,

View File

@@ -51,13 +51,10 @@ compile_error!("io_uring is a linux only feature.");
use std::future::Future;
use tokio::task::JoinHandle;
// Cannot define a main macro when compiled into test harness.
// Workaround for https://github.com/rust-lang/rust/issues/62127.
#[cfg(all(feature = "macros", not(test)))]
pub use actix_macros::main;
#[cfg(feature = "macros")]
pub use actix_macros::test;
@@ -65,12 +62,13 @@ mod arbiter;
mod runtime;
mod system;
pub use tokio::pin;
use tokio::task::JoinHandle;
pub use self::arbiter::{Arbiter, ArbiterHandle};
pub use self::runtime::Runtime;
pub use self::system::{System, SystemRunner};
pub use tokio::pin;
pub mod signal {
//! Asynchronous signal handling (Tokio re-exports).
@@ -95,7 +93,6 @@ pub mod net {
use tokio::io::{AsyncRead, AsyncWrite, Interest};
pub use tokio::net::UdpSocket;
pub use tokio::net::{TcpListener, TcpSocket, TcpStream};
#[cfg(unix)]
pub use tokio::net::{UnixDatagram, UnixListener, UnixStream};
@@ -198,6 +195,7 @@ pub mod task {
/// assert!(handle.await.unwrap_err().is_cancelled());
/// # });
/// ```
#[track_caller]
#[inline]
pub fn spawn<Fut>(f: Fut) -> JoinHandle<Fut::Output>
where

View File

@@ -53,6 +53,7 @@ impl Runtime {
/// # Panics
/// This function panics if the spawn fails. Failure occurs if the executor is currently at
/// capacity and is unable to spawn a new future.
#[track_caller]
pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
where
F: Future + 'static,
@@ -73,6 +74,7 @@ impl Runtime {
///
/// The caller is responsible for ensuring that other spawned futures complete execution by
/// calling `block_on` or `run`.
#[track_caller]
pub fn block_on<F>(&self, f: F) -> F::Output
where
F: Future,

View File

@@ -46,7 +46,6 @@ impl System {
/// Create a new System using the [Tokio Runtime](tokio-runtime) returned from a closure.
///
/// [tokio-runtime]: tokio::runtime::Runtime
#[doc(hidden)]
pub fn with_tokio_rt<F>(runtime_factory: F) -> SystemRunner
where
F: Fn() -> tokio::runtime::Runtime,
@@ -205,6 +204,7 @@ impl SystemRunner {
}
/// Runs the provided future, blocking the current thread until the future completes.
#[track_caller]
#[inline]
pub fn block_on<F: Future>(&self, fut: F) -> F::Output {
self.rt.block_on(fut)

View File

@@ -4,7 +4,6 @@ use std::{
};
use actix_rt::{task::JoinError, Arbiter, System};
#[cfg(not(feature = "io-uring"))]
use {
std::{sync::mpsc::channel, thread},

View File

@@ -1,6 +1,39 @@
# Changes
## Unreleased - 2021-xx-xx
## Unreleased - 2022-xx-xx
## 2.1.1 - 2022-03-09
- No significant changes since `2.1.0`.
## 2.1.0 - 2022-03-08
- Update `tokio-uring` dependency to `0.3.0`. [#448]
- Logs emitted now use the `tracing` crate with `log` compatibility. [#448]
- Wait for accept thread to stop before sending completion signal. [#443]
[#443]: https://github.com/actix/actix-net/pull/443
[#448]: https://github.com/actix/actix-net/pull/448
## 2.0.0 - 2022-01-19
- No significant changes since `2.0.0-rc.4`.
## 2.0.0-rc.4 - 2022-01-12
- Update `tokio-uring` dependency to `0.2.0`. [#436]
[#436]: https://github.com/actix/actix-net/pull/436
## 2.0.0-rc.3 - 2021-12-31
- No significant changes since `2.0.0-rc.2`.
## 2.0.0-rc.2 - 2021-12-27
- Simplify `TestServer`. [#431]
[#431]: https://github.com/actix/actix-net/pull/431
## 2.0.0-rc.1 - 2021-12-05

View File

@@ -1,14 +1,17 @@
[package]
name = "actix-server"
version = "2.0.0-rc.1"
version = "2.1.1"
authors = [
"Nikolay Kim <fafhrd91@gmail.com>",
"fakeshadow <24548779@qq.com>",
"Rob Ede <robjtede@icloud.com>",
"Ali MJ Al-Nasrawy <alimjalnasrawy@gmail.com>",
]
description = "General purpose TCP server built for the Actix ecosystem"
keywords = ["network", "framework", "async", "futures"]
repository = "https://github.com/actix/actix-net.git"
keywords = ["network", "tcp", "server", "framework", "async"]
categories = ["network-programming", "asynchronous"]
homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-net.git"
license = "MIT OR Apache-2.0"
edition = "2018"
@@ -21,26 +24,27 @@ default = []
io-uring = ["tokio-uring", "actix-rt/io-uring"]
[dependencies]
actix-rt = { version = "2.4.0", default-features = false }
actix-service = "2.0.0"
actix-utils = "3.0.0"
actix-rt = { version = "2.7", default-features = false }
actix-service = "2"
actix-utils = "3"
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
futures-util = { version = "0.3.7", default-features = false, features = ["alloc"] }
log = "0.4"
mio = { version = "0.8", features = ["os-poll", "net"] }
num_cpus = "1.13"
socket2 = "0.4.2"
tokio = { version = "1.5.1", features = ["sync"] }
tokio = { version = "1.13.1", features = ["sync"] }
tracing = { version = "0.1.30", default-features = false, features = ["log"] }
# runtime for io-uring feature
tokio-uring = { version = "0.1", optional = true }
# runtime for `io-uring` feature
[target.'cfg(target_os = "linux")'.dependencies]
tokio-uring = { version = "0.3", optional = true }
[dev-dependencies]
actix-codec = "0.4.0"
actix-rt = "2.4.0"
actix-codec = "0.5.0"
actix-rt = "2.6.0"
bytes = "1"
env_logger = "0.9"
futures-util = { version = "0.3.7", default-features = false, features = ["sink", "async-await-macro"] }
tokio = { version = "1.5.1", features = ["io-util", "rt-multi-thread", "macros"] }
tokio = { version = "1.13.1", features = ["io-util", "rt-multi-thread", "macros", "fs"] }

15
actix-server/README.md Normal file
View File

@@ -0,0 +1,15 @@
# actix-server
> General purpose TCP server built for the Actix ecosystem.
[![crates.io](https://img.shields.io/crates/v/actix-server?label=latest)](https://crates.io/crates/actix-server)
[![Documentation](https://docs.rs/actix-server/badge.svg?version=2.1.1)](https://docs.rs/actix-server/2.1.1)
[![Version](https://img.shields.io/badge/rustc-1.52+-ab6000.svg)](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
![License](https://img.shields.io/crates/l/actix-server.svg)
[![Dependency Status](https://deps.rs/crate/actix-server/2.1.1/status.svg)](https://deps.rs/crate/actix-server/2.1.1)
![Download](https://img.shields.io/crates/d/actix-server.svg)
[![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/NWpN5mmg3x)
## Resources
- [Library Documentation](https://docs.rs/actix-server)
- [Examples](/actix-server/examples)

View File

@@ -0,0 +1,95 @@
//! Simple file-reader TCP server with framed stream.
//!
//! Using the following command:
//!
//! ```sh
//! nc 127.0.0.1 8080
//! ```
//!
//! Follow the prompt and enter a file path, relative or absolute.
use std::io;
use actix_codec::{Framed, LinesCodec};
use actix_rt::net::TcpStream;
use actix_server::Server;
use actix_service::{fn_service, ServiceFactoryExt as _};
use futures_util::{SinkExt as _, StreamExt as _};
use tokio::{fs::File, io::AsyncReadExt as _};
async fn run() -> io::Result<()> {
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
let addr = ("127.0.0.1", 8080);
tracing::info!("starting server on port: {}", &addr.0);
// Bind socket address and start worker(s). By default, the server uses the number of physical
// 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("file-reader", addr, move || {
fn_service(move |stream: TcpStream| async move {
// set up codec to use with I/O resource
let mut framed = Framed::new(stream, LinesCodec::default());
loop {
// prompt for file name
framed.send("Type file name to return:").await?;
// wait for next line
match framed.next().await {
Some(Ok(line)) => {
match File::open(&line).await {
Ok(mut file) => {
tracing::info!("reading file: {}", &line);
// read file into String buffer
let mut buf = String::new();
file.read_to_string(&mut buf).await?;
// send String into framed object
framed.send(buf).await?;
// break out of loop and
break;
}
Err(err) => {
tracing::error!("{}", err);
framed
.send("File not found or not readable. Try again.")
.await?;
continue;
}
};
}
// not being able to read a line from the stream is unrecoverable
Some(Err(err)) => return Err(err),
// This EOF won't be hit.
None => continue,
}
}
// close connection after file has been copied to TCP stream
Ok(())
})
.map_err(|err| tracing::error!("Service Error: {:?}", err))
})?
.workers(2)
.run()
.await
}
#[tokio::main]
async fn main() -> io::Result<()> {
run().await?;
Ok(())
}
// alternatively:
// #[actix_rt::main]
// async fn main() -> io::Result<()> {
// run().await?;
// Ok(())
// }

View File

@@ -22,16 +22,15 @@ use actix_server::Server;
use actix_service::{fn_service, ServiceFactoryExt as _};
use bytes::BytesMut;
use futures_util::future::ok;
use log::{error, info};
use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _};
async fn run() -> io::Result<()> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
let count = Arc::new(AtomicUsize::new(0));
let addr = ("127.0.0.1", 8080);
info!("starting server on port: {}", &addr.0);
tracing::info!("starting server on port: {}", &addr.0);
// Bind socket address and start worker(s). By default, the server uses the number of physical
// CPU cores as the worker count. For this reason, the closure passed to bind needs to return
@@ -58,14 +57,14 @@ async fn run() -> io::Result<()> {
// more bytes to process
Ok(bytes_read) => {
info!("[{}] read {} bytes", num, bytes_read);
tracing::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);
tracing::error!("Stream Error: {:?}", err);
return Err(());
}
}
@@ -75,10 +74,10 @@ async fn run() -> io::Result<()> {
Ok((buf.freeze(), size))
}
})
.map_err(|err| error!("Service Error: {:?}", err))
.map_err(|err| tracing::error!("Service Error: {:?}", err))
.and_then(move |(_, size)| {
let num = num2.load(Ordering::SeqCst);
info!("[{}] total bytes read: {}", num, size);
tracing::info!("[{}] total bytes read: {}", num, size);
ok(size)
})
})?

View File

@@ -1,8 +1,8 @@
use std::{io, thread, time::Duration};
use actix_rt::time::Instant;
use log::{debug, error, info};
use mio::{Interest, Poll, Token as MioToken};
use tracing::{debug, error, info};
use crate::{
availability::Availability,
@@ -41,7 +41,7 @@ impl Accept {
pub(crate) fn start(
sockets: Vec<(usize, MioListener)>,
builder: &ServerBuilder,
) -> io::Result<(WakerQueue, Vec<WorkerHandleServer>)> {
) -> io::Result<(WakerQueue, Vec<WorkerHandleServer>, thread::JoinHandle<()>)> {
let handle_server = ServerHandle::new(builder.cmd_tx.clone());
// construct poll instance and its waker
@@ -73,12 +73,12 @@ impl Accept {
handle_server,
)?;
thread::Builder::new()
let accept_handle = thread::Builder::new()
.name("actix-server acceptor".to_owned())
.spawn(move || accept.poll_with(&mut sockets))
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
Ok((waker_queue, handles_server))
Ok((waker_queue, handles_server, accept_handle))
}
fn new_with_sockets(
@@ -127,10 +127,10 @@ impl Accept {
let mut events = mio::Events::with_capacity(256);
loop {
if let Err(e) = self.poll.poll(&mut events, self.timeout) {
match e.kind() {
if let Err(err) = self.poll.poll(&mut events, self.timeout) {
match err.kind() {
io::ErrorKind::Interrupted => {}
_ => panic!("Poll error: {}", e),
_ => panic!("Poll error: {}", err),
}
}
@@ -298,15 +298,15 @@ impl Accept {
fn register_logged(&self, info: &mut ServerSocketInfo) {
match self.register(info) {
Ok(_) => debug!("Resume accepting connections on {}", info.lst.local_addr()),
Err(e) => error!("Can not register server socket {}", e),
Err(err) => error!("Can not register server socket {}", err),
}
}
fn deregister_logged(&self, info: &mut ServerSocketInfo) {
match self.poll.registry().deregister(&mut info.lst) {
Ok(_) => debug!("Paused accepting connections on {}", info.lst.local_addr()),
Err(e) => {
error!("Can not deregister server socket {}", e)
Err(err) => {
error!("Can not deregister server socket {}", err)
}
}
}
@@ -396,10 +396,10 @@ impl Accept {
let conn = Conn { io, token };
self.accept_one(conn);
}
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => return,
Err(ref e) if connection_error(e) => continue,
Err(e) => {
error!("Error accepting connection: {}", e);
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => return,
Err(ref err) if connection_error(err) => continue,
Err(err) => {
error!("Error accepting connection: {}", err);
// deregister listener temporary
self.deregister_logged(info);

View File

@@ -1,12 +1,12 @@
use std::{io, time::Duration};
use actix_rt::net::TcpStream;
use log::{info, trace};
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
use tracing::{info, trace};
use crate::{
server::ServerCommand,
service::{InternalServiceFactory, ServiceFactory, StreamNewService},
service::{InternalServiceFactory, ServerServiceFactory, StreamNewService},
socket::{
create_mio_tcp_listener, MioListener, MioTcpListener, StdTcpListener, ToSocketAddrs,
},
@@ -140,10 +140,11 @@ impl ServerBuilder {
}
/// Add new service to the server.
pub fn bind<F, U, N: AsRef<str>>(mut self, name: N, addr: U, factory: F) -> io::Result<Self>
pub fn bind<F, U, N>(mut self, name: N, addr: U, factory: F) -> io::Result<Self>
where
F: ServiceFactory<TcpStream>,
F: ServerServiceFactory<TcpStream>,
U: ToSocketAddrs,
N: AsRef<str>,
{
let sockets = bind_addr(addr, self.backlog)?;
@@ -172,7 +173,7 @@ impl ServerBuilder {
factory: F,
) -> io::Result<Self>
where
F: ServiceFactory<TcpStream>,
F: ServerServiceFactory<TcpStream>,
{
lst.set_nonblocking(true)?;
let addr = lst.local_addr()?;
@@ -213,16 +214,16 @@ impl ServerBuilder {
/// Add new unix domain service to the server.
pub fn bind_uds<F, U, N>(self, name: N, addr: U, factory: F) -> io::Result<Self>
where
F: ServiceFactory<actix_rt::net::UnixStream>,
F: ServerServiceFactory<actix_rt::net::UnixStream>,
N: AsRef<str>,
U: AsRef<std::path::Path>,
{
// The path must not exist when we try to bind.
// Try to remove it to avoid bind error.
if let Err(e) = std::fs::remove_file(addr.as_ref()) {
if let Err(err) = std::fs::remove_file(addr.as_ref()) {
// NotFound is expected and not an issue. Anything else is.
if e.kind() != std::io::ErrorKind::NotFound {
return Err(e);
if err.kind() != std::io::ErrorKind::NotFound {
return Err(err);
}
}
@@ -240,7 +241,7 @@ impl ServerBuilder {
factory: F,
) -> io::Result<Self>
where
F: ServiceFactory<actix_rt::net::UnixStream>,
F: ServerServiceFactory<actix_rt::net::UnixStream>,
{
use std::net::{IpAddr, Ipv4Addr};
lst.set_nonblocking(true)?;
@@ -263,22 +264,23 @@ pub(super) fn bind_addr<S: ToSocketAddrs>(
addr: S,
backlog: u32,
) -> io::Result<Vec<MioTcpListener>> {
let mut err = None;
let mut opt_err = None;
let mut success = false;
let mut sockets = Vec::new();
for addr in addr.to_socket_addrs()? {
match create_mio_tcp_listener(addr, backlog) {
Ok(lst) => {
success = true;
sockets.push(lst);
}
Err(e) => err = Some(e),
Err(err) => opt_err = Some(err),
}
}
if success {
Ok(sockets)
} else if let Some(err) = err.take() {
} else if let Some(err) = opt_err.take() {
Err(err)
} else {
Err(io::Error::new(

View File

@@ -63,10 +63,10 @@ impl<T> Future for JoinAll<T> {
#[cfg(test)]
mod test {
use super::*;
use actix_utils::future::ready;
use super::*;
#[actix_rt::test]
async fn test_join_all() {
let futs = vec![ready(Ok(1)), ready(Err(3)), ready(Ok(9))];

View File

@@ -21,11 +21,10 @@ mod worker;
pub use self::builder::ServerBuilder;
pub use self::handle::ServerHandle;
pub use self::server::Server;
pub use self::service::ServiceFactory;
pub use self::test_server::TestServer;
pub use self::service::ServerServiceFactory;
#[doc(hidden)]
pub use self::socket::FromStream;
pub use self::test_server::TestServer;
/// Start server building process
#[doc(hidden)]

View File

@@ -3,14 +3,15 @@ use std::{
io, mem,
pin::Pin,
task::{Context, Poll},
thread,
time::Duration,
};
use actix_rt::{time::sleep, System};
use futures_core::{future::BoxFuture, Stream};
use futures_util::stream::StreamExt as _;
use log::{error, info};
use tokio::sync::{mpsc::UnboundedReceiver, oneshot};
use tracing::{error, info};
use crate::{
accept::Accept,
@@ -65,7 +66,7 @@ pub(crate) enum ServerCommand {
/// server has fully shut down.
///
/// # Shutdown Signals
/// On UNIX systems, `SIGQUIT` will start a graceful shutdown and `SIGTERM` or `SIGINT` will start a
/// On UNIX systems, `SIGTERM` will start a graceful shutdown and `SIGQUIT` or `SIGINT` will start a
/// forced shutdown. On Windows, a Ctrl-C signal will start a forced shutdown.
///
/// A graceful shutdown will wait for all workers to stop first.
@@ -158,6 +159,7 @@ impl Future for Server {
pub struct ServerInner {
worker_handles: Vec<WorkerHandleServer>,
accept_handle: Option<thread::JoinHandle<()>>,
worker_config: ServerWorkerConfig,
services: Vec<Box<dyn InternalServiceFactory>>,
waker_queue: WakerQueue,
@@ -205,7 +207,7 @@ impl ServerInner {
);
}
let (waker_queue, worker_handles) = Accept::start(sockets, &builder)?;
let (waker_queue, worker_handles, accept_handle) = Accept::start(sockets, &builder)?;
let mux = ServerEventMultiplexer {
signal_fut: (builder.listen_os_signals).then(Signals::new),
@@ -214,6 +216,7 @@ impl ServerInner {
let server = ServerInner {
waker_queue,
accept_handle: Some(accept_handle),
worker_handles,
worker_config: builder.worker_config,
services: builder.factories,
@@ -243,7 +246,8 @@ impl ServerInner {
} => {
self.stopping = true;
// stop accept thread
// Signal accept thread to stop.
// Signal is non-blocking; we wait for thread to stop later.
self.waker_queue.wake(WakerInterest::Stop);
// send stop signal to workers
@@ -258,6 +262,13 @@ impl ServerInner {
let _ = join_all(workers_stop).await;
}
// wait for accept thread stop
self.accept_handle
.take()
.unwrap()
.join()
.expect("Accept thread must not panic in any case");
if let Some(tx) = completion {
let _ = tx.send(());
}

View File

@@ -1,16 +1,21 @@
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::task::{Context, Poll};
use std::{
marker::PhantomData,
net::SocketAddr,
task::{Context, Poll},
};
use actix_service::{Service, ServiceFactory as BaseServiceFactory};
use actix_utils::future::{ready, Ready};
use futures_core::future::LocalBoxFuture;
use log::error;
use tracing::error;
use crate::socket::{FromStream, MioStream};
use crate::worker::WorkerCounterGuard;
use crate::{
socket::{FromStream, MioStream},
worker::WorkerCounterGuard,
};
pub trait ServiceFactory<Stream: FromStream>: Send + Clone + 'static {
#[doc(hidden)]
pub trait ServerServiceFactory<Stream: FromStream>: Send + Clone + 'static {
type Factory: BaseServiceFactory<Stream, Config = ()>;
fn create(&self) -> Self::Factory;
@@ -72,15 +77,15 @@ where
});
Ok(())
}
Err(e) => {
error!("Can not convert to an async tcp stream: {}", e);
Err(err) => {
error!("Can not convert to an async tcp stream: {}", err);
Err(())
}
})
}
}
pub(crate) struct StreamNewService<F: ServiceFactory<Io>, Io: FromStream> {
pub(crate) struct StreamNewService<F: ServerServiceFactory<Io>, Io: FromStream> {
name: String,
inner: F,
token: usize,
@@ -90,7 +95,7 @@ pub(crate) struct StreamNewService<F: ServiceFactory<Io>, Io: FromStream> {
impl<F, Io> StreamNewService<F, Io>
where
F: ServiceFactory<Io>,
F: ServerServiceFactory<Io>,
Io: FromStream + Send + 'static,
{
pub(crate) fn create(
@@ -111,7 +116,7 @@ where
impl<F, Io> InternalServiceFactory for StreamNewService<F, Io>
where
F: ServiceFactory<Io>,
F: ServerServiceFactory<Io>,
Io: FromStream + Send + 'static,
{
fn name(&self, _: usize) -> &str {
@@ -143,7 +148,7 @@ where
}
}
impl<F, T, I> ServiceFactory<I> for F
impl<F, T, I> ServerServiceFactory<I> for F
where
F: Fn() -> T + Send + Clone + 'static,
T: BaseServiceFactory<I, Config = ()>,

View File

@@ -5,7 +5,7 @@ use std::{
task::{Context, Poll},
};
use log::trace;
use tracing::trace;
/// Types of process signals.
// #[allow(dead_code)]
@@ -69,7 +69,7 @@ impl Signals {
unix::signal(*kind)
.map(|tokio_sig| (*sig, tokio_sig))
.map_err(|e| {
log::error!(
tracing::error!(
"Can not initialize stream handler for {:?} err: {}",
sig,
e

View File

@@ -1,19 +1,17 @@
pub(crate) use std::net::{
SocketAddr as StdSocketAddr, TcpListener as StdTcpListener, ToSocketAddrs,
};
use std::{fmt, io};
use actix_rt::net::TcpStream;
pub(crate) use mio::net::TcpListener as MioTcpListener;
use mio::{event::Source, Interest, Registry, Token};
#[cfg(unix)]
pub(crate) use {
mio::net::UnixListener as MioUnixListener,
std::os::unix::net::UnixListener as StdUnixListener,
};
use std::{fmt, io};
use actix_rt::net::TcpStream;
use mio::{event::Source, Interest, Registry, Token};
pub(crate) enum MioListener {
Tcp(MioTcpListener),
#[cfg(unix)]

View File

@@ -2,7 +2,7 @@ use std::{io, net, sync::mpsc, thread};
use actix_rt::{net::TcpStream, System};
use crate::{Server, ServerBuilder, ServerHandle, ServiceFactory};
use crate::{Server, ServerBuilder, ServerHandle, ServerServiceFactory};
/// A testing server.
///
@@ -16,7 +16,7 @@ use crate::{Server, ServerBuilder, ServerHandle, ServiceFactory};
///
/// #[actix_rt::main]
/// async fn main() {
/// let srv = TestServer::with(|| fn_service(
/// let srv = TestServer::start(|| fn_service(
/// |sock| async move {
/// println!("New connection: {:?}", sock);
/// Ok::<_, ()>(())
@@ -28,8 +28,8 @@ use crate::{Server, ServerBuilder, ServerHandle, ServiceFactory};
/// ```
pub struct TestServer;
/// Test server runtime
pub struct TestServerRuntime {
/// Test server handle.
pub struct TestServerHandle {
addr: net::SocketAddr,
host: String,
port: u16,
@@ -38,46 +38,26 @@ pub struct TestServerRuntime {
}
impl TestServer {
/// Start new server with server builder.
pub fn start<F>(mut factory: F) -> TestServerRuntime
where
F: FnMut(ServerBuilder) -> ServerBuilder + Send + 'static,
{
let (tx, rx) = mpsc::channel();
// run server in separate thread
let thread_handle = thread::spawn(move || {
System::new().block_on(async {
let server = factory(Server::build()).workers(1).disable_signals().run();
tx.send(server.handle()).unwrap();
server.await
})
});
let server_handle = rx.recv().unwrap();
TestServerRuntime {
addr: "127.0.0.1:0".parse().unwrap(),
host: "127.0.0.1".to_string(),
port: 0,
server_handle,
thread_handle: Some(thread_handle),
}
/// Start new `TestServer` using application factory and default server config.
pub fn start(factory: impl ServerServiceFactory<TcpStream>) -> TestServerHandle {
Self::start_with_builder(Server::build(), factory)
}
/// Start new test server with application factory.
pub fn with<F: ServiceFactory<TcpStream>>(factory: F) -> TestServerRuntime {
/// Start new `TestServer` using application factory and server builder.
pub fn start_with_builder(
server_builder: ServerBuilder,
factory: impl ServerServiceFactory<TcpStream>,
) -> TestServerHandle {
let (tx, rx) = mpsc::channel();
// run server in separate thread
let thread_handle = thread::spawn(move || {
let sys = System::new();
let tcp = net::TcpListener::bind("127.0.0.1:0").unwrap();
let local_addr = tcp.local_addr().unwrap();
let lst = net::TcpListener::bind("127.0.0.1:0").unwrap();
let local_addr = lst.local_addr().unwrap();
sys.block_on(async {
let server = Server::build()
.listen("test", tcp, factory)
System::new().block_on(async {
let server = server_builder
.listen("test", lst, factory)
.unwrap()
.workers(1)
.disable_signals()
@@ -93,7 +73,7 @@ impl TestServer {
let host = format!("{}", addr.ip());
let port = addr.port();
TestServerRuntime {
TestServerHandle {
addr,
host,
port,
@@ -107,17 +87,19 @@ impl TestServer {
use socket2::{Domain, Protocol, Socket, Type};
let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap();
let socket =
Socket::new(Domain::for_address(addr), Type::STREAM, Some(Protocol::TCP)).unwrap();
let domain = Domain::for_address(addr);
let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP)).unwrap();
socket.set_reuse_address(true).unwrap();
socket.set_nonblocking(true).unwrap();
socket.bind(&addr.into()).unwrap();
socket.listen(1024).unwrap();
net::TcpListener::from(socket).local_addr().unwrap()
}
}
impl TestServerRuntime {
impl TestServerHandle {
/// Test server host.
pub fn host(&self) -> &str {
&self.host
@@ -140,12 +122,12 @@ impl TestServerRuntime {
}
/// Connect to server, returning a Tokio `TcpStream`.
pub fn connect(&self) -> std::io::Result<TcpStream> {
pub fn connect(&self) -> io::Result<TcpStream> {
TcpStream::from_std(net::TcpStream::connect(self.addr)?)
}
}
impl Drop for TestServerRuntime {
impl Drop for TestServerHandle {
fn drop(&mut self) {
self.stop()
}
@@ -158,8 +140,14 @@ mod tests {
use super::*;
#[tokio::test]
async fn plain_tokio_runtime() {
let srv = TestServer::with(|| fn_service(|_sock| async move { Ok::<_, ()>(()) }));
async fn connect_in_tokio_runtime() {
let srv = TestServer::start(|| fn_service(|_sock| async move { Ok::<_, ()>(()) }));
assert!(srv.connect().is_ok());
}
#[actix_rt::test]
async fn connect_in_actix_runtime() {
let srv = TestServer::start(|| fn_service(|_sock| async move { Ok::<_, ()>(()) }));
assert!(srv.connect().is_ok());
}
}

View File

@@ -17,11 +17,11 @@ use actix_rt::{
Arbiter, ArbiterHandle, System,
};
use futures_core::{future::LocalBoxFuture, ready};
use log::{error, info, trace};
use tokio::sync::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
oneshot,
};
use tracing::{error, info, trace};
use crate::{
service::{BoxedServerService, InternalServiceFactory},

View File

@@ -26,20 +26,54 @@ fn test_bind() {
let srv = Server::build()
.workers(1)
.disable_signals()
.shutdown_timeout(3600)
.bind("test", addr, move || {
fn_service(|_| async { Ok::<_, ()>(()) })
})?
.run();
let _ = tx.send(srv.handle());
tx.send(srv.handle()).unwrap();
srv.await
})
});
let srv = rx.recv().unwrap();
thread::sleep(Duration::from_millis(500));
assert!(net::TcpStream::connect(addr).is_ok());
net::TcpStream::connect(addr).unwrap();
let _ = srv.stop(true);
h.join().unwrap().unwrap();
}
#[test]
fn test_listen() {
let addr = unused_addr();
let (tx, rx) = mpsc::channel();
let lst = net::TcpListener::bind(addr).unwrap();
let h = thread::spawn(move || {
actix_rt::System::new().block_on(async {
let srv = Server::build()
.workers(1)
.disable_signals()
.shutdown_timeout(3600)
.listen("test", lst, move || {
fn_service(|_| async { Ok::<_, ()>(()) })
})?
.run();
tx.send(srv.handle()).unwrap();
srv.await
})
});
let srv = rx.recv().unwrap();
thread::sleep(Duration::from_millis(500));
net::TcpStream::connect(addr).unwrap();
let _ = srv.stop(true);
h.join().unwrap().unwrap();
@@ -80,38 +114,6 @@ fn plain_tokio_runtime() {
h.join().unwrap().unwrap();
}
#[test]
fn test_listen() {
let addr = unused_addr();
let lst = net::TcpListener::bind(addr).unwrap();
let (tx, rx) = mpsc::channel();
let h = thread::spawn(move || {
actix_rt::System::new().block_on(async {
let srv = Server::build()
.disable_signals()
.workers(1)
.listen("test", lst, move || {
fn_service(|_| async { Ok::<_, ()>(()) })
})?
.run();
let _ = tx.send(srv.handle());
srv.await
})
});
let srv = rx.recv().unwrap();
thread::sleep(Duration::from_millis(500));
assert!(net::TcpStream::connect(addr).is_ok());
let _ = srv.stop(true);
h.join().unwrap().unwrap();
}
#[test]
#[cfg(unix)]
fn test_start() {
@@ -252,6 +254,7 @@ async fn test_max_concurrent_connections() {
h.join().unwrap().unwrap();
}
// TODO: race-y failures detected due to integer underflow when calling Counter::total
#[actix_rt::test]
async fn test_service_restart() {
use std::task::{Context, Poll};

View File

@@ -0,0 +1,73 @@
use std::net;
use actix_rt::net::TcpStream;
use actix_server::{Server, TestServer};
use actix_service::fn_service;
use bytes::BytesMut;
use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _};
macro_rules! await_timeout_ms {
($fut:expr, $limit:expr) => {
::actix_rt::time::timeout(::std::time::Duration::from_millis($limit), $fut)
.await
.unwrap()
.unwrap();
};
}
#[tokio::test]
async fn testing_server_echo() {
let srv = TestServer::start(|| {
fn_service(move |mut stream: TcpStream| async move {
let mut size = 0;
let mut buf = BytesMut::new();
match stream.read_buf(&mut buf).await {
Ok(0) => return Err(()),
Ok(bytes_read) => {
stream.write_all(&buf[size..]).await.unwrap();
size += bytes_read;
}
Err(_) => return Err(()),
}
Ok((buf.freeze(), size))
})
});
let mut conn = srv.connect().unwrap();
await_timeout_ms!(conn.write_all(b"test"), 200);
let mut buf = Vec::new();
await_timeout_ms!(conn.read_to_end(&mut buf), 200);
assert_eq!(&buf, b"test".as_ref());
}
#[tokio::test]
async fn new_with_builder() {
let alt_addr = TestServer::unused_addr();
let srv = TestServer::start_with_builder(
Server::build()
.bind("alt", alt_addr, || {
fn_service(|_| async { Ok::<_, ()>(()) })
})
.unwrap(),
|| {
fn_service(|mut sock: TcpStream| async move {
let mut buf = [0u8; 16];
sock.read_exact(&mut buf).await
})
},
);
// connect to test server
srv.connect().unwrap();
// connect to alt service defined in custom ServerBuilder
TcpStream::from_std(net::TcpStream::connect(alt_addr).unwrap()).unwrap();
}

View File

@@ -1,6 +1,7 @@
# Changes
## Unreleased - 2021-xx-xx
## Unreleased - 2022-xx-xx
- Minimum supported Rust version (MSRV) is now 1.49.
## 2.0.2 - 2021-12-18

View File

@@ -394,9 +394,10 @@ mod tests {
#[actix_rt::test]
async fn test_auto_impl_send() {
use crate::{map_config, ServiceExt, ServiceFactoryExt};
use alloc::rc::Rc;
use crate::{map_config, ServiceExt, ServiceFactoryExt};
let srv_1 = fn_service(|_: Rc<u8>| ok::<_, Rc<u8>>(Rc::new(0u8)));
let fac_1 = fn_factory_with_config(|_: Rc<u8>| {

View File

@@ -38,10 +38,9 @@ pub use self::apply_cfg::{apply_cfg, apply_cfg_factory};
pub use self::ext::{ServiceExt, ServiceFactoryExt, TransformExt};
pub use self::fn_service::{fn_factory, fn_factory_with_config, fn_service};
pub use self::map_config::{map_config, unit_config};
pub use self::transform::{apply, ApplyTransform, Transform};
#[allow(unused_imports)]
use self::ready::{err, ok, ready, Ready};
pub use self::transform::{apply, ApplyTransform, Transform};
/// An asynchronous operation from `Request` to a `Response`.
///

View File

@@ -97,7 +97,7 @@ where
match this.fut.poll(cx) {
Poll::Ready(Ok(resp)) => Poll::Ready(Ok((this.f)(resp))),
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
Poll::Pending => Poll::Pending,
}
}

View File

@@ -1,10 +1,30 @@
# Changes
## Unreleased - 2021-xx-xx
## Unreleased - 2022-xx-xx
## 3.0.4 - 2022-03-15
- Logs emitted now use the `tracing` crate with `log` compatibility. [#451]
[#451]: https://github.com/actix/actix-net/pull/451
## 3.0.3 - 2022-02-15
- No significant changes since `3.0.2`.
## 3.0.2 - 2022-01-28
- Expose `connect::Connection::new`. [#439]
[#439]: https://github.com/actix/actix-net/pull/439
## 3.0.1 - 2022-01-11
- No significant changes since `3.0.0`.
## 3.0.0 - 2021-12-26
* No significant changes since `3.0.0-rc.2`.
- No significant changes since `3.0.0-rc.2`.
## 3.0.0-rc.2 - 2021-12-10
@@ -12,6 +32,7 @@
[#429]: https://github.com/actix/actix-net/pull/429
## 3.0.0-rc.1 - 2021-11-29
### Added
- Derive `Debug` for `connect::Connection`. [#422]
@@ -117,7 +138,7 @@
[#273]: https://github.com/actix/actix-net/pull/273
## 3.0.0-beta.2 - 2021-xx-xx
## 3.0.0-beta.2 - 2022-xx-xx
- Depend on stable trust-dns packages. [#204]
[#204]: https://github.com/actix/actix-net/pull/204

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-tls"
version = "3.0.0"
version = "3.0.4"
authors = [
"Nikolay Kim <fafhrd91@gmail.com>",
"Rob Ede <robjtede@icloud.com>",
@@ -42,16 +42,15 @@ native-tls = ["tokio-native-tls"]
uri = ["http"]
[dependencies]
actix-codec = "0.4.0"
actix-codec = "0.5.0"
actix-rt = { version = "2.2.0", default-features = false }
actix-service = "2.0.0"
actix-utils = "3.0.0"
derive_more = "0.99.5"
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
log = "0.4"
pin-project-lite = "0.2.7"
tokio-util = { version = "0.6.3", default-features = false }
tokio-util = "0.7"
tracing = { version = "0.1.30", default-features = false, features = ["log"] }
# uri
http = { version = "0.2.3", optional = true }
@@ -69,7 +68,7 @@ tokio-native-tls = { version = "0.3", optional = true }
[dev-dependencies]
actix-rt = "2.2.0"
actix-server = "2.0.0-rc.1"
actix-server = "2.0.0"
bytes = "1"
env_logger = "0.9"
futures-util = { version = "0.3.7", default-features = false, features = ["sink"] }

View File

@@ -15,8 +15,9 @@
//! http --verify=false https://127.0.0.1:8443
//! ```
// this use only exists because of how we have organised the crate
// it is not necessary for your actual code
#[rustfmt::skip]
// this `use` is only exists because of how we have organised the crate
// it is not necessary for your actual code; you should import from `rustls` directly
use tokio_rustls::rustls;
use std::{
@@ -34,9 +35,9 @@ use actix_server::Server;
use actix_service::ServiceFactoryExt as _;
use actix_tls::accept::rustls::{Acceptor as RustlsAcceptor, TlsStream};
use futures_util::future::ok;
use log::info;
use rustls::{server::ServerConfig, Certificate, PrivateKey};
use rustls_pemfile::{certs, rsa_private_keys};
use tracing::info;
#[actix_rt::main]
async fn main() -> io::Result<()> {

View File

@@ -2,11 +2,12 @@
use std::{
convert::Infallible,
error::Error,
fmt,
sync::atomic::{AtomicUsize, Ordering},
};
use actix_utils::counter::Counter;
use derive_more::{Display, Error};
#[cfg(feature = "openssl")]
#[cfg_attr(docsrs, doc(cfg(feature = "openssl")))]
@@ -43,23 +44,45 @@ pub fn max_concurrent_tls_connect(num: usize) {
/// TLS handshake error, TLS timeout, or inner service error.
///
/// All TLS acceptors from this crate will return the `SvcErr` type parameter as [`Infallible`],
/// which can be cast to your own service type, inferred or otherwise,
/// using [`into_service_error`](Self::into_service_error).
#[derive(Debug, Display, Error)]
/// which can be cast to your own service type, inferred or otherwise, using [`into_service_error`].
///
/// [`into_service_error`]: Self::into_service_error
#[derive(Debug)]
pub enum TlsError<TlsErr, SvcErr> {
/// TLS handshake has timed-out.
#[display(fmt = "TLS handshake has timed-out")]
Timeout,
/// Wraps TLS service errors.
#[display(fmt = "TLS handshake error")]
Tls(TlsErr),
/// Wraps service errors.
#[display(fmt = "Service error")]
Service(SvcErr),
}
impl<TlsErr, SvcErr> fmt::Display for TlsError<TlsErr, SvcErr> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Timeout => f.write_str("TLS handshake has timed-out"),
Self::Tls(_) => f.write_str("TLS handshake error"),
Self::Service(_) => f.write_str("Service error"),
}
}
}
impl<TlsErr, SvcErr> Error for TlsError<TlsErr, SvcErr>
where
TlsErr: Error + 'static,
SvcErr: Error + 'static,
{
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
TlsError::Tls(err) => Some(err),
TlsError::Service(err) => Some(err),
TlsError::Timeout => None,
}
}
}
impl<TlsErr> TlsError<TlsErr, Infallible> {
/// Casts the infallible service error type returned from acceptors into caller's type.
///

View File

@@ -20,11 +20,11 @@ use actix_utils::{
counter::Counter,
future::{ready, Ready as FutReady},
};
use derive_more::{Deref, DerefMut, From};
use futures_core::future::LocalBoxFuture;
use tokio_native_tls::{native_tls::Error, TlsAcceptor};
use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER};
use crate::impl_more;
pub mod reexports {
//! Re-exports from `native-tls` that are useful for acceptors.
@@ -33,9 +33,12 @@ pub mod reexports {
}
/// Wraps a `native-tls` based async TLS stream in order to implement [`ActixStream`].
#[derive(Deref, DerefMut, From)]
pub struct TlsStream<IO>(tokio_native_tls::TlsStream<IO>);
impl_more::from! { tokio_native_tls::TlsStream<IO> => TlsStream<IO> }
impl_more::deref! { TlsStream<IO> => 0: tokio_native_tls::TlsStream<IO> }
impl_more::deref_mut! { TlsStream<IO> => 0 }
impl<IO: ActixStream> AsyncRead for TlsStream<IO> {
fn poll_read(
self: Pin<&mut Self>,

View File

@@ -21,11 +21,11 @@ use actix_utils::{
counter::{Counter, CounterGuard},
future::{ready, Ready as FutReady},
};
use derive_more::{Deref, DerefMut, From};
use openssl::ssl::{Error, Ssl, SslAcceptor};
use pin_project_lite::pin_project;
use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER};
use crate::impl_more;
pub mod reexports {
//! Re-exports from `openssl` that are useful for acceptors.
@@ -36,9 +36,12 @@ pub mod reexports {
}
/// Wraps an `openssl` based async TLS stream in order to implement [`ActixStream`].
#[derive(Deref, DerefMut, From)]
pub struct TlsStream<IO>(tokio_openssl::SslStream<IO>);
impl_more::from! { tokio_openssl::SslStream<IO> => TlsStream<IO> }
impl_more::deref! { TlsStream<IO> => 0: tokio_openssl::SslStream<IO> }
impl_more::deref_mut! { TlsStream<IO> => 0 }
impl<IO: ActixStream> AsyncRead for TlsStream<IO> {
fn poll_read(
self: Pin<&mut Self>,

View File

@@ -22,12 +22,12 @@ use actix_utils::{
counter::{Counter, CounterGuard},
future::{ready, Ready as FutReady},
};
use derive_more::{Deref, DerefMut, From};
use pin_project_lite::pin_project;
use tokio_rustls::rustls::ServerConfig;
use tokio_rustls::{Accept, TlsAcceptor};
use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER};
use crate::impl_more;
pub mod reexports {
//! Re-exports from `rustls` that are useful for acceptors.
@@ -36,9 +36,12 @@ pub mod reexports {
}
/// Wraps a `rustls` based async TLS stream in order to implement [`ActixStream`].
#[derive(Deref, DerefMut, From)]
pub struct TlsStream<IO>(tokio_rustls::server::TlsStream<IO>);
impl_more::from! { tokio_rustls::server::TlsStream<IO> => TlsStream<IO> }
impl_more::deref! { TlsStream<IO> => 0: tokio_rustls::server::TlsStream<IO> }
impl_more::deref_mut! { TlsStream<IO> => 0 }
impl<IO: ActixStream> AsyncRead for TlsStream<IO> {
fn poll_read(
self: Pin<&mut Self>,

View File

@@ -1,20 +1,19 @@
use derive_more::{Deref, DerefMut};
use super::Host;
use crate::impl_more;
/// Wraps underlying I/O and the connection request that initiated it.
#[derive(Debug, Deref, DerefMut)]
#[derive(Debug)]
pub struct Connection<R, IO> {
pub(crate) req: R,
#[deref]
#[deref_mut]
pub(crate) io: IO,
}
impl_more::deref! { Connection<R, IO> => io: IO }
impl_more::deref_mut! { Connection<R, IO> => io }
impl<R, IO> Connection<R, IO> {
/// Construct new `Connection` from request and IO parts.
pub(crate) fn new(req: R, io: IO) -> Self {
pub fn new(req: R, io: IO) -> Self {
Self { req, io }
}
}

View File

@@ -1,30 +1,38 @@
use std::{error::Error, io};
use derive_more::Display;
use std::{error::Error, fmt, io};
/// Errors that can result from using a connector service.
#[derive(Debug, Display)]
#[derive(Debug)]
pub enum ConnectError {
/// Failed to resolve the hostname
#[display(fmt = "Failed resolving hostname")]
/// Failed to resolve the hostname.
Resolver(Box<dyn std::error::Error>),
/// No DNS records
#[display(fmt = "No DNS records found for the input")]
/// No DNS records.
NoRecords,
/// Invalid input
/// Invalid input.
InvalidInput,
/// Unresolved host name
#[display(fmt = "Connector received `Connect` method with unresolved host")]
/// Unresolved host name.
Unresolved,
/// Connection IO error
#[display(fmt = "{}", _0)]
/// Connection IO error.
Io(io::Error),
}
impl fmt::Display for ConnectError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NoRecords => f.write_str("No DNS records found for the input"),
Self::InvalidInput => f.write_str("Invalid input"),
Self::Unresolved => {
f.write_str("Connector received `Connect` method with unresolved host")
}
Self::Resolver(_) => f.write_str("Failed to resolve hostname"),
Self::Io(_) => f.write_str("I/O error"),
}
}
}
impl Error for ConnectError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {

View File

@@ -27,25 +27,25 @@ pub trait Host: Unpin + 'static {
impl Host for String {
fn hostname(&self) -> &str {
self.split_once(':')
str_split_once(self, ':')
.map(|(hostname, _)| hostname)
.unwrap_or(self)
}
fn port(&self) -> Option<u16> {
self.split_once(':').and_then(|(_, port)| port.parse().ok())
str_split_once(self, ':').and_then(|(_, port)| port.parse().ok())
}
}
impl Host for &'static str {
fn hostname(&self) -> &str {
self.split_once(':')
str_split_once(self, ':')
.map(|(hostname, _)| hostname)
.unwrap_or(self)
}
fn port(&self) -> Option<u16> {
self.split_once(':').and_then(|(_, port)| port.parse().ok())
str_split_once(self, ':').and_then(|(_, port)| port.parse().ok())
}
}
@@ -69,3 +69,11 @@ mod tests {
assert_connection_info_eq!("example.com:false:false", "example.com", None);
}
}
// `str::split_once` is stabilized in 1.52.0
fn str_split_once(str: &str, delimiter: char) -> Option<(&str, &str)> {
let mut splitn = str.splitn(2, delimiter);
let prefix = splitn.next()?;
let suffix = splitn.next()?;
Some((prefix, suffix))
}

View File

@@ -8,11 +8,11 @@ use actix_rt::net::ActixStream;
use actix_service::{Service, ServiceFactory};
use actix_utils::future::{ok, Ready};
use futures_core::future::LocalBoxFuture;
use log::trace;
use tokio_native_tls::{
native_tls::TlsConnector as NativeTlsConnector, TlsConnector as AsyncNativeTlsConnector,
TlsStream as AsyncTlsStream,
};
use tracing::trace;
use crate::connect::{Connection, Host};
@@ -20,7 +20,6 @@ pub mod reexports {
//! Re-exports from `native-tls` and `tokio-native-tls` that are useful for connectors.
pub use tokio_native_tls::native_tls::TlsConnector;
pub use tokio_native_tls::TlsStream as AsyncTlsStream;
}

View File

@@ -13,9 +13,9 @@ use actix_rt::net::ActixStream;
use actix_service::{Service, ServiceFactory};
use actix_utils::future::{ok, Ready};
use futures_core::ready;
use log::trace;
use openssl::ssl::SslConnector;
use tokio_openssl::SslStream as AsyncSslStream;
use tracing::trace;
use crate::connect::{Connection, Host};
@@ -25,7 +25,6 @@ pub mod reexports {
pub use openssl::ssl::{
Error, HandshakeError, SslConnector, SslConnectorBuilder, SslMethod,
};
pub use tokio_openssl::SslStream as AsyncSslStream;
}
@@ -141,9 +140,12 @@ where
trace!("SSL Handshake success: {:?}", stream.hostname());
Poll::Ready(Ok(stream.replace_io(this.io.take().unwrap()).1))
}
Err(e) => {
trace!("SSL Handshake error: {:?}", e);
Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, format!("{}", e))))
Err(err) => {
trace!("SSL Handshake error: {:?}", err);
Poll::Ready(Err(io::Error::new(
io::ErrorKind::Other,
format!("{}", err),
)))
}
}
}

View File

@@ -12,7 +12,7 @@ use actix_rt::task::{spawn_blocking, JoinHandle};
use actix_service::{Service, ServiceFactory};
use actix_utils::future::{ok, Ready};
use futures_core::{future::LocalBoxFuture, ready};
use log::trace;
use tracing::trace;
use super::{ConnectError, ConnectInfo, Host, Resolve};
@@ -164,8 +164,8 @@ impl<R: Host> Future for ResolverFut<R> {
Self::LookUp(fut, req) => {
let res = match ready!(Pin::new(fut).poll(cx)) {
Ok(Ok(res)) => Ok(res),
Ok(Err(e)) => Err(ConnectError::Resolver(Box::new(e))),
Err(e) => Err(ConnectError::Io(e.into())),
Ok(Err(err)) => Err(ConnectError::Resolver(Box::new(err))),
Err(err) => Err(ConnectError::Io(err.into())),
};
let req = req.take().unwrap();

View File

@@ -15,10 +15,10 @@ use actix_rt::net::ActixStream;
use actix_service::{Service, ServiceFactory};
use actix_utils::future::{ok, Ready};
use futures_core::ready;
use log::trace;
use tokio_rustls::rustls::{client::ServerName, OwnedTrustAnchor, RootCertStore};
use tokio_rustls::{client::TlsStream as AsyncTlsStream, rustls::ClientConfig};
use tokio_rustls::{Connect as RustlsConnect, TlsConnector as RustlsTlsConnector};
use tracing::trace;
use webpki_roots::TLS_SERVER_ROOTS;
use crate::connect::{Connection, Host};
@@ -26,10 +26,8 @@ use crate::connect::{Connection, Host};
pub mod reexports {
//! Re-exports from `rustls` and `webpki_roots` that are useful for connectors.
pub use tokio_rustls::rustls::ClientConfig;
pub use tokio_rustls::client::TlsStream as AsyncTlsStream;
pub use tokio_rustls::rustls::ClientConfig;
pub use webpki_roots::TLS_SERVER_ROOTS;
}

View File

@@ -15,8 +15,8 @@ use actix_rt::net::{TcpSocket, TcpStream};
use actix_service::{Service, ServiceFactory};
use actix_utils::future::{ok, Ready};
use futures_core::ready;
use log::{error, trace};
use tokio_util::sync::ReusableBoxFuture;
use tracing::{error, trace};
use super::{connect_addrs::ConnectAddrs, error::ConnectError, ConnectInfo, Connection, Host};
@@ -79,7 +79,7 @@ pub enum TcpConnectorFut<R> {
port: u16,
local_addr: Option<IpAddr>,
addrs: Option<VecDeque<SocketAddr>>,
stream: ReusableBoxFuture<Result<TcpStream, io::Error>>,
stream: ReusableBoxFuture<'static, Result<TcpStream, io::Error>>,
},
Error(Option<ConnectError>),

View File

@@ -0,0 +1,40 @@
/// A helper to implement `Deref` for a type.
#[macro_export]
macro_rules! deref {
($ty:ident $(<$($generic:ident),*>)? => $field:tt: $target:ty) => {
impl $(<$($generic),*>)? ::core::ops::Deref for $ty $(<$($generic),*>)? {
type Target = $target;
fn deref(&self) -> &Self::Target {
&self.$field
}
}
};
}
/// A helper to implement `DerefMut` for a type.
#[macro_export]
macro_rules! deref_mut {
($ty:ident $(<$($generic:ident),*>)? => $field:tt) => {
impl $(<$($generic),*>)? ::core::ops::DerefMut for $ty $(<$($generic),*>)? {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.$field
}
}
};
}
/// A helper to implement `From` for a unit struct.
#[macro_export]
macro_rules! from {
($from:ty => $ty:ident $(<$($generic:ident),*>)?) => {
impl $(<$($generic),*>)? ::core::convert::From<$from> for $ty $(<$($generic),*>)? {
fn from(from: $from) -> Self {
Self(from)
}
}
};
}
#[allow(unused_imports)]
pub(crate) use crate::{deref, deref_mut, from};

View File

@@ -18,3 +18,5 @@ pub mod accept;
#[cfg(feature = "connect")]
#[cfg_attr(docsrs, doc(cfg(feature = "connect")))]
pub mod connect;
mod impl_more;

View File

@@ -51,13 +51,13 @@ fn openssl_acceptor(cert: String, key: String) -> tls_openssl::ssl::SslAcceptor
mod danger {
use std::time::SystemTime;
use super::*;
use tokio_rustls::rustls::{
self,
client::{ServerCertVerified, ServerCertVerifier},
};
use super::*;
pub struct NoCertificateVerification;
impl ServerCertVerifier for NoCertificateVerification {
@@ -94,7 +94,7 @@ fn rustls_connector(_cert: String, _key: String) -> ClientConfig {
async fn accepts_connections() {
let (cert, key) = new_cert_and_key();
let srv = TestServer::with({
let srv = TestServer::start({
let cert = cert.clone();
let key = key.clone();

View File

@@ -74,7 +74,7 @@ fn openssl_connector(cert: String, key: String) -> SslConnector {
async fn accepts_connections() {
let (cert, key) = new_cert_and_key();
let srv = TestServer::with({
let srv = TestServer::start({
let cert = cert.clone();
let key = key.clone();

View File

@@ -9,15 +9,14 @@ use actix_codec::{BytesCodec, Framed};
use actix_rt::net::TcpStream;
use actix_server::TestServer;
use actix_service::{fn_service, Service, ServiceFactory};
use actix_tls::connect::{ConnectError, ConnectInfo, Connection, Connector, Host};
use bytes::Bytes;
use futures_util::sink::SinkExt;
use actix_tls::connect::{ConnectError, ConnectInfo, Connection, Connector, Host};
#[cfg(feature = "openssl")]
#[actix_rt::test]
async fn test_string() {
let srv = TestServer::with(|| {
let srv = TestServer::start(|| {
fn_service(|io: TcpStream| async {
let mut framed = Framed::new(io, BytesCodec);
framed.send(Bytes::from_static(b"test")).await?;
@@ -34,7 +33,7 @@ async fn test_string() {
#[cfg(feature = "rustls")]
#[actix_rt::test]
async fn test_rustls_string() {
let srv = TestServer::with(|| {
let srv = TestServer::start(|| {
fn_service(|io: TcpStream| async {
let mut framed = Framed::new(io, BytesCodec);
framed.send(Bytes::from_static(b"test")).await?;
@@ -50,7 +49,7 @@ async fn test_rustls_string() {
#[actix_rt::test]
async fn test_static_str() {
let srv = TestServer::with(|| {
let srv = TestServer::start(|| {
fn_service(|io: TcpStream| async {
let mut framed = Framed::new(io, BytesCodec);
framed.send(Bytes::from_static(b"test")).await?;
@@ -81,7 +80,7 @@ async fn service_factory() {
Connector::default()
}
let srv = TestServer::with(|| {
let srv = TestServer::start(|| {
fn_service(|io: TcpStream| async {
let mut framed = Framed::new(io, BytesCodec);
framed.send(Bytes::from_static(b"test")).await?;
@@ -101,7 +100,7 @@ async fn service_factory() {
async fn test_openssl_uri() {
use std::convert::TryFrom;
let srv = TestServer::with(|| {
let srv = TestServer::start(|| {
fn_service(|io: TcpStream| async {
let mut framed = Framed::new(io, BytesCodec);
framed.send(Bytes::from_static(b"test")).await?;
@@ -120,7 +119,7 @@ async fn test_openssl_uri() {
async fn test_rustls_uri() {
use std::convert::TryFrom;
let srv = TestServer::with(|| {
let srv = TestServer::start(|| {
fn_service(|io: TcpStream| async {
let mut framed = Framed::new(io, BytesCodec);
framed.send(Bytes::from_static(b"test")).await?;
@@ -136,7 +135,7 @@ async fn test_rustls_uri() {
#[actix_rt::test]
async fn test_local_addr() {
let srv = TestServer::with(|| {
let srv = TestServer::start(|| {
fn_service(|io: TcpStream| async {
let mut framed = Framed::new(io, BytesCodec);
framed.send(Bytes::from_static(b"test")).await?;

View File

@@ -8,11 +8,10 @@ use std::{
use actix_rt::net::TcpStream;
use actix_server::TestServer;
use actix_service::{fn_service, Service, ServiceFactory};
use futures_core::future::LocalBoxFuture;
use actix_tls::connect::{
ConnectError, ConnectInfo, Connection, Connector, Host, Resolve, Resolver,
};
use futures_core::future::LocalBoxFuture;
#[actix_rt::test]
async fn custom_resolver() {
@@ -53,7 +52,7 @@ async fn custom_resolver_connect() {
use trust_dns_resolver::TokioAsyncResolver;
let srv =
TestServer::with(|| fn_service(|_io: TcpStream| async { Ok::<_, io::Error>(()) }));
TestServer::start(|| fn_service(|_io: TcpStream| async { Ok::<_, io::Error>(()) }));
struct MyResolver {
trust_dns: TokioAsyncResolver,

View File

@@ -1,5 +1,8 @@
# Changes
## [0.1.0] - 2020-01-15
## Unreleased - 2022-xx-xx
- Minimum supported Rust version (MSRV) is now 1.49.
## 0.1.0 - 2020-01-15
- Initial release

View File

@@ -118,8 +118,6 @@ where
#[cfg(test)]
mod test {
use super::*;
use std::cell::RefCell;
use std::collections::{BTreeMap, BTreeSet};
use std::sync::{Arc, RwLock};
@@ -128,6 +126,8 @@ mod test {
use slab::Slab;
use tracing::{span, Event, Level, Metadata, Subscriber};
use super::*;
thread_local! {
static SPAN: RefCell<Vec<span::Id>> = RefCell::new(Vec::new());
}

View File

@@ -1,6 +1,7 @@
# Changes
## Unreleased - 2021-xx-xx
## Unreleased - 2022-xx-xx
- Minimum supported Rust version (MSRV) is now 1.49.
## 3.0.0 - 2021-04-16

View File

@@ -1,6 +1,7 @@
# Changes
## Unreleased - 2021-xx-xx
## Unreleased - 2022-xx-xx
- Minimum supported Rust version (MSRV) is now 1.49.
## 1.0.0 - 2020-12-31

View File

@@ -219,11 +219,11 @@ mod serde {
#[cfg(test)]
mod serde_impl_tests {
use super::*;
use serde::de::DeserializeOwned;
use static_assertions::assert_impl_all;
use super::*;
assert_impl_all!(ByteString: Serialize, DeserializeOwned);
}
}

View File

@@ -1,6 +1,10 @@
# Changes
## Unreleased - 2021-xx-xx
## Unreleased - 2022-xx-xx
## 0.1.3 - 2022-05-03
- Minimum supported Rust version (MSRV) is now 1.49.
## 0.1.2 - 2021-04-01

View File

@@ -1,6 +1,6 @@
[package]
name = "local-channel"
version = "0.1.2"
version = "0.1.3"
description = "A non-threadsafe multi-producer, single-consumer, futures-aware, FIFO queue"
authors = [
"Nikolay Kim <fafhrd91@gmail.com>",
@@ -18,4 +18,4 @@ futures-util = { version = "0.3.7", default-features = false }
local-waker = "0.1"
[dev-dependencies]
tokio = { version = "1.5.1", features = ["rt", "macros"] }
tokio = { version = "1.13.1", features = ["rt", "macros"] }

View File

@@ -0,0 +1 @@
../LICENSE-APACHE

1
local-channel/LICENSE-MIT Symbolic link
View File

@@ -0,0 +1 @@
../LICENSE-MIT

View File

@@ -1,6 +1,10 @@
# Changes
## Unreleased - 2021-xx-xx
## Unreleased - 2022-xx-xx
## 0.1.3 - 2022-05-03
- Minimum supported Rust version (MSRV) is now 1.49.
## 0.1.2 - 2021-12-18

View File

@@ -1,6 +1,6 @@
[package]
name = "local-waker"
version = "0.1.2"
version = "0.1.3"
description = "A synchronization primitive for thread-local task wakeup"
authors = [
"Nikolay Kim <fafhrd91@gmail.com>",

1
local-waker/LICENSE-APACHE Symbolic link
View File

@@ -0,0 +1 @@
../LICENSE-APACHE

1
local-waker/LICENSE-MIT Symbolic link
View File

@@ -0,0 +1 @@
../LICENSE-MIT

View File

@@ -1,2 +1,2 @@
max_width = 96
reorder_imports = true
group_imports = "StdExternalCrate"