mirror of
https://github.com/fafhrd91/actix-net
synced 2025-08-12 16:47:05 +02:00
Compare commits
21 Commits
rt-v2.5.1
...
codec-v0.5
Author | SHA1 | Date | |
---|---|---|---|
|
217cbd2228 | ||
|
d229c1e886 | ||
|
6792f799a6 | ||
|
72481313cc | ||
|
59b629c74b | ||
|
7988694242 | ||
|
b8a7741524 | ||
|
5e290d76f8 | ||
|
0edb64575f | ||
|
941f67dec9 | ||
|
3e624b8376 | ||
|
26446fdbad | ||
|
b7b7bd2cbf | ||
|
637625f9b7 | ||
|
b1d5d85e72 | ||
|
ed2c07b304 | ||
|
4fe7fec5ef | ||
|
4c9ee88ec4 | ||
|
9ec3cc0fe7 | ||
|
01e0f922de | ||
|
10d3bb6d0d |
182
.github/workflows/ci-master.yml
vendored
Normal file
182
.github/workflows/ci-master.yml
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
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
|
34
.github/workflows/ci.yml
vendored
34
.github/workflows/ci.yml
vendored
@@ -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 }}
|
||||
@@ -88,7 +87,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,7 +117,7 @@ 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)
|
||||
runs-on: ubuntu-latest
|
||||
@@ -146,35 +145,6 @@ jobs:
|
||||
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
|
||||
|
11
README.md
11
README.md
@@ -2,18 +2,19 @@
|
||||
|
||||
> A collection of lower-level libraries for composable network services.
|
||||
|
||||
[](https://github.com/actix/actix-net/actions/workflows/ci.yml)
|
||||
[](https://github.com/actix/actix-net/actions/workflows/ci.yml)
|
||||
[](https://codecov.io/gh/actix/actix-net)
|
||||
[](https://discord.gg/NWpN5mmg3x)
|
||||
[](https://deps.rs/repo/github/actix/actix-extras)
|
||||
[](https://deps.rs/repo/github/actix/actix-net)
|
||||
|
||||
## Example
|
||||
## Examples
|
||||
|
||||
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.
|
||||
Most crates in this repo's have a Minimum Supported Rust Version (MSRV) of 1.46.0. Only `actix-tls`
|
||||
and `actix-server` have MSRV of 1.52.0.
|
||||
|
||||
## License
|
||||
|
||||
|
@@ -3,6 +3,12 @@
|
||||
## Unreleased - 2021-xx-xx
|
||||
|
||||
|
||||
## 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`.
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "actix-codec"
|
||||
version = "0.4.2"
|
||||
version = "0.5.0"
|
||||
authors = [
|
||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||
"Rob Ede <robjtede@icloud.com>",
|
||||
@@ -17,7 +17,7 @@ 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 }
|
||||
@@ -25,7 +25,7 @@ log = "0.4"
|
||||
memchr = "2.3"
|
||||
pin-project-lite = "0.2"
|
||||
tokio = "1.13.1"
|
||||
tokio-util = { version = "0.6", features = ["codec", "io"] }
|
||||
tokio-util = { version = "0.7", features = ["codec", "io"] }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.3", features = ["html_reports"] }
|
||||
|
@@ -193,7 +193,7 @@ 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))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ impl<T, U> Framed<T, U> {
|
||||
log::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,
|
||||
};
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -50,7 +50,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 +67,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 +99,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(())),
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,12 @@
|
||||
## Unreleased - 2021-xx-xx
|
||||
|
||||
|
||||
## 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]
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "actix-rt"
|
||||
version = "2.5.1"
|
||||
version = "2.6.0"
|
||||
authors = [
|
||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||
"Rob Ede <robjtede@icloud.com>",
|
||||
@@ -29,9 +29,10 @@ actix-macros = { version = "0.2.3", optional = true }
|
||||
futures-core = { version = "0.3", default-features = false }
|
||||
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.2", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.13.1", features = ["full"] }
|
||||
hyper = { version = "0.14", default-features = false, features = ["server", "tcp", "http1"] }
|
||||
hyper = { version = "0.14.10", default-features = false, features = ["server", "tcp", "http1"] }
|
||||
|
@@ -3,11 +3,11 @@
|
||||
> Tokio-based single-threaded async runtime for the Actix ecosystem.
|
||||
|
||||
[](https://crates.io/crates/actix-rt)
|
||||
[](https://docs.rs/actix-rt/2.5.1)
|
||||
[](https://docs.rs/actix-rt/2.6.0)
|
||||
[](https://blog.rust-lang.org/2020/03/12/Rust-1.46.html)
|
||||

|
||||
<br />
|
||||
[](https://deps.rs/crate/actix-rt/2.5.1)
|
||||
[](https://deps.rs/crate/actix-rt/2.6.0)
|
||||

|
||||
[](https://discord.gg/WghFtEH6Hb)
|
||||
|
||||
|
@@ -21,8 +21,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);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@@ -3,6 +3,16 @@
|
||||
## Unreleased - 2021-xx-xx
|
||||
|
||||
|
||||
## 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`.
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "actix-server"
|
||||
version = "2.0.0-rc.3"
|
||||
version = "2.0.0"
|
||||
authors = [
|
||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||
"fakeshadow <24548779@qq.com>",
|
||||
@@ -24,7 +24,7 @@ default = []
|
||||
io-uring = ["tokio-uring", "actix-rt/io-uring"]
|
||||
|
||||
[dependencies]
|
||||
actix-rt = { version = "2.4.0", default-features = false }
|
||||
actix-rt = { version = "2.6.0", default-features = false }
|
||||
actix-service = "2.0.0"
|
||||
actix-utils = "3.0.0"
|
||||
|
||||
@@ -37,11 +37,12 @@ socket2 = "0.4.2"
|
||||
tokio = { version = "1.13.1", features = ["sync"] }
|
||||
|
||||
# runtime for io-uring feature
|
||||
tokio-uring = { version = "0.1", optional = true }
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
tokio-uring = { version = "0.2", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
actix-codec = "0.4.2"
|
||||
actix-rt = "2.4.0"
|
||||
actix-codec = "0.5.0"
|
||||
actix-rt = "2.6.0"
|
||||
|
||||
bytes = "1"
|
||||
env_logger = "0.9"
|
||||
|
15
actix-server/README.md
Normal file
15
actix-server/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# actix-server
|
||||
|
||||
> General purpose TCP server built for the Actix ecosystem.
|
||||
|
||||
[](https://crates.io/crates/actix-server)
|
||||
[](https://docs.rs/actix-server/2.0.0)
|
||||
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
||||

|
||||
[](https://deps.rs/crate/actix-server/2.0.0)
|
||||

|
||||
[](https://discord.gg/NWpN5mmg3x)
|
||||
|
||||
## Resources
|
||||
- [Library Documentation](https://docs.rs/actix-server)
|
||||
- [Examples](/actix-server/examples)
|
@@ -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);
|
||||
|
@@ -220,10 +220,10 @@ impl ServerBuilder {
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,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(
|
||||
|
@@ -77,8 +77,8 @@ 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(())
|
||||
}
|
||||
})
|
||||
|
@@ -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,
|
||||
}
|
||||
}
|
||||
|
@@ -3,8 +3,22 @@
|
||||
## Unreleased - 2021-xx-xx
|
||||
|
||||
|
||||
## 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 +26,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]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "actix-tls"
|
||||
version = "3.0.0"
|
||||
version = "3.0.3"
|
||||
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.2"
|
||||
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"
|
||||
|
||||
# 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.3"
|
||||
actix-server = "2.0.0"
|
||||
bytes = "1"
|
||||
env_logger = "0.9"
|
||||
futures-util = { version = "0.3.7", default-features = false, features = ["sink"] }
|
||||
|
@@ -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.
|
||||
///
|
||||
|
@@ -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>,
|
||||
|
@@ -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>,
|
||||
|
@@ -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>,
|
||||
|
@@ -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 }
|
||||
}
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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))
|
||||
}
|
||||
|
@@ -141,9 +141,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),
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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();
|
||||
|
@@ -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>),
|
||||
|
40
actix-tls/src/impl_more.rs
Normal file
40
actix-tls/src/impl_more.rs
Normal 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};
|
@@ -18,3 +18,5 @@ pub mod accept;
|
||||
#[cfg(feature = "connect")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "connect")))]
|
||||
pub mod connect;
|
||||
|
||||
mod impl_more;
|
||||
|
Reference in New Issue
Block a user