mirror of
https://github.com/fafhrd91/actix-net
synced 2025-08-14 04:10:34 +02:00
Compare commits
39 Commits
tls-v3.0.0
...
server-v2.
Author | SHA1 | Date | |
---|---|---|---|
|
4b6a581ef3 | ||
|
3e132d2bc6 | ||
|
c5d6174cec | ||
|
77d4a69b2f | ||
|
ae5377fd6e | ||
|
bd9bda0504 | ||
|
41ed48219d | ||
|
7804ed12eb | ||
|
2a54065fae | ||
|
217cbd2228 | ||
|
d229c1e886 | ||
|
6792f799a6 | ||
|
72481313cc | ||
|
59b629c74b | ||
|
7988694242 | ||
|
b8a7741524 | ||
|
5e290d76f8 | ||
|
0edb64575f | ||
|
941f67dec9 | ||
|
3e624b8376 | ||
|
26446fdbad | ||
|
b7b7bd2cbf | ||
|
637625f9b7 | ||
|
b1d5d85e72 | ||
|
ed2c07b304 | ||
|
4fe7fec5ef | ||
|
4c9ee88ec4 | ||
|
9ec3cc0fe7 | ||
|
01e0f922de | ||
|
10d3bb6d0d | ||
|
3ba4eafde5 | ||
|
5faa98f6d2 | ||
|
b552d847ed | ||
|
5058e2d14e | ||
|
ae9afd4de7 | ||
|
01d2f18f68 | ||
|
e92b5aaf31 | ||
|
459a6d1b02 | ||
|
9935883905 |
213
.github/workflows/ci-master.yml
vendored
Normal file
213
.github/workflows/ci-master.yml
vendored
Normal 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
|
52
.github/workflows/ci.yml
vendored
52
.github/workflows/ci.yml
vendored
@@ -20,7 +20,6 @@ jobs:
|
|||||||
version:
|
version:
|
||||||
- 1.52.0 # MSRV for -server and -tls
|
- 1.52.0 # MSRV for -server and -tls
|
||||||
- stable
|
- stable
|
||||||
- nightly
|
|
||||||
|
|
||||||
name: ${{ matrix.target.name }} / ${{ matrix.version }}
|
name: ${{ matrix.target.name }} / ${{ matrix.version }}
|
||||||
runs-on: ${{ matrix.target.os }}
|
runs-on: ${{ matrix.target.os }}
|
||||||
@@ -88,7 +87,7 @@ jobs:
|
|||||||
if: matrix.target.triple == 'x86_64-pc-windows-gnu'
|
if: matrix.target.triple == 'x86_64-pc-windows-gnu'
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with: { command: ci-check-min }
|
with: { command: ci-check-min }
|
||||||
|
|
||||||
- name: check full
|
- name: check full
|
||||||
# TODO: compile OpenSSL and run tests on MinGW
|
# TODO: compile OpenSSL and run tests on MinGW
|
||||||
if: >
|
if: >
|
||||||
@@ -118,17 +117,17 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cargo install cargo-cache --version 0.6.2 --no-default-features --features ci-autoclean
|
cargo install cargo-cache --version 0.6.2 --no-default-features --features ci-autoclean
|
||||||
cargo-cache
|
cargo-cache
|
||||||
|
|
||||||
build_and_test_lower_msrv:
|
build_and_test_lower_msrv:
|
||||||
name: Linux / 1.46 (lower MSRV)
|
name: Linux / 1.49 (lower MSRV)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- 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
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: 1.46.0-x86_64-unknown-linux-gnu
|
toolchain: 1.49.0-x86_64-unknown-linux-gnu
|
||||||
profile: minimal
|
profile: minimal
|
||||||
override: true
|
override: true
|
||||||
|
|
||||||
@@ -138,43 +137,24 @@ jobs:
|
|||||||
command: install
|
command: install
|
||||||
args: cargo-hack
|
args: cargo-hack
|
||||||
|
|
||||||
|
- name: Generate Cargo.lock
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with: { command: generate-lockfile }
|
||||||
|
|
||||||
|
- name: Tweak lockfile
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: update
|
||||||
|
args: -p=rustls --precise=0.20.2
|
||||||
|
|
||||||
- name: tests
|
- name: tests
|
||||||
run: |
|
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
|
- name: Clear the cargo caches
|
||||||
run: |
|
run: |
|
||||||
cargo install cargo-cache --version 0.6.2 --no-default-features --features ci-autoclean
|
cargo install cargo-cache --version 0.6.2 --no-default-features --features ci-autoclean
|
||||||
cargo-cache
|
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:
|
rustdoc:
|
||||||
name: rustdoc
|
name: rustdoc
|
||||||
|
26
README.md
26
README.md
@@ -2,29 +2,25 @@
|
|||||||
|
|
||||||
> A collection of lower-level libraries for composable network services.
|
> A collection of lower-level libraries for composable network services.
|
||||||
|
|
||||||

|
[](https://github.com/actix/actix-net/actions/workflows/ci.yml)
|
||||||
[](https://codecov.io/gh/actix/actix-net)
|
[](https://codecov.io/gh/actix/actix-net)
|
||||||
[](https://discord.gg/NWpN5mmg3x)
|
[](https://discord.gg/NWpN5mmg3x)
|
||||||
|
[](https://deps.rs/repo/github/actix/actix-net)
|
||||||
|
|
||||||
## Build statuses
|
## Examples
|
||||||
| Platform | Build Status |
|
|
||||||
| ---------------- | ------------ |
|
|
||||||
| Linux | [](https://github.com/actix/actix-net/actions?query=workflow%3A"CI+(Linux)") |
|
|
||||||
| macOS | [](https://github.com/actix/actix-net/actions?query=workflow%3A"CI+(macOS)") |
|
|
||||||
| Windows | [](https://github.com/actix/actix-net/actions?query=workflow%3A"CI+(Windows)") |
|
|
||||||
| Windows (MinGW) | [](https://github.com/actix/actix-net/actions?query=workflow%3A"CI+(Windows-mingw)") |
|
|
||||||
|
|
||||||
## Example
|
See example folders for [`actix-server`](./actix-server/examples) and [`actix-tls`](./actix-tls/examples).
|
||||||
See `actix-server/examples` and `actix-tls/examples` for some basic examples.
|
|
||||||
|
|
||||||
### MSRV
|
## 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.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
|
## 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))
|
The crates in repo are licensed under either of:
|
||||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or [http://opensource.org/licenses/MIT](http://opensource.org/licenses/MIT))
|
|
||||||
|
- 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.
|
at your option.
|
||||||
|
|
||||||
|
@@ -1,6 +1,17 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2022-xx-xx
|
||||||
|
- Minimum supported Rust version (MSRV) is now 1.49.
|
||||||
|
|
||||||
|
|
||||||
|
## 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
|
## 0.4.1 - 2021-11-05
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-codec"
|
name = "actix-codec"
|
||||||
version = "0.4.1"
|
version = "0.5.0"
|
||||||
authors = [
|
authors = [
|
||||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||||
"Rob Ede <robjtede@icloud.com>",
|
"Rob Ede <robjtede@icloud.com>",
|
||||||
@@ -17,15 +17,15 @@ name = "actix_codec"
|
|||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "1.2.1"
|
bitflags = "1.2"
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
futures-core = { version = "0.3.7", default-features = false }
|
futures-core = { version = "0.3.7", default-features = false }
|
||||||
futures-sink = { version = "0.3.7", default-features = false }
|
futures-sink = { version = "0.3.7", default-features = false }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
memchr = "2.3"
|
memchr = "2.3"
|
||||||
pin-project-lite = "0.2"
|
pin-project-lite = "0.2"
|
||||||
tokio = "1.5.1"
|
tokio = "1.13.1"
|
||||||
tokio-util = { version = "0.6", features = ["codec", "io"] }
|
tokio-util = { version = "0.7", features = ["codec", "io"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = { version = "0.3", features = ["html_reports"] }
|
criterion = { version = "0.3", features = ["html_reports"] }
|
||||||
|
@@ -156,7 +156,7 @@ impl<T, U> Framed<T, U> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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>
|
pub fn write<I>(mut self: Pin<&mut Self>, item: I) -> Result<(), <U as Encoder<I>>::Error>
|
||||||
where
|
where
|
||||||
T: AsyncWrite,
|
T: AsyncWrite,
|
||||||
@@ -193,7 +193,7 @@ impl<T, U> Framed<T, U> {
|
|||||||
match this.codec.decode_eof(this.read_buf) {
|
match this.codec.decode_eof(this.read_buf) {
|
||||||
Ok(Some(frame)) => return Poll::Ready(Some(Ok(frame))),
|
Ok(Some(frame)) => return Poll::Ready(Some(Ok(frame))),
|
||||||
Ok(None) => return Poll::Ready(None),
|
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");
|
log::trace!("frame decoded from buffer");
|
||||||
return Poll::Ready(Some(Ok(frame)));
|
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
|
_ => (), // 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) {
|
let cnt = match tokio_util::io::poll_read_buf(this.io, cx, this.read_buf) {
|
||||||
Poll::Pending => return Poll::Pending,
|
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,
|
Poll::Ready(Ok(cnt)) => cnt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -7,8 +7,8 @@ use super::{Decoder, Encoder};
|
|||||||
|
|
||||||
/// Lines codec. Reads/writes line delimited strings.
|
/// 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
|
/// Will split input up by LF or CRLF delimiters. Carriage return characters at the end of lines are
|
||||||
/// lines are not preserved.
|
/// not preserved.
|
||||||
#[derive(Debug, Copy, Clone, Default)]
|
#[derive(Debug, Copy, Clone, Default)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct LinesCodec;
|
pub struct LinesCodec;
|
||||||
|
@@ -50,7 +50,7 @@ impl Write for Bilateral {
|
|||||||
assert_eq!(&data[..], &src[..data.len()]);
|
assert_eq!(&data[..], &src[..data.len()]);
|
||||||
Ok(data.len())
|
Ok(data.len())
|
||||||
}
|
}
|
||||||
Some(Err(e)) => Err(e),
|
Some(Err(err)) => Err(err),
|
||||||
None => panic!("unexpected write; {:?}", src),
|
None => panic!("unexpected write; {:?}", src),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,13 +67,13 @@ impl AsyncWrite for Bilateral {
|
|||||||
buf: &[u8],
|
buf: &[u8],
|
||||||
) -> Poll<Result<usize, io::Error>> {
|
) -> Poll<Result<usize, io::Error>> {
|
||||||
match Pin::get_mut(self).write(buf) {
|
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),
|
other => Ready(other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
|
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
|
||||||
match Pin::get_mut(self).flush() {
|
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),
|
other => Ready(other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,8 +99,8 @@ impl AsyncRead for Bilateral {
|
|||||||
buf.put_slice(&data);
|
buf.put_slice(&data);
|
||||||
Ready(Ok(()))
|
Ready(Ok(()))
|
||||||
}
|
}
|
||||||
Some(Err(ref e)) if e.kind() == WouldBlock => Pending,
|
Some(Err(ref err)) if err.kind() == WouldBlock => Pending,
|
||||||
Some(Err(e)) => Ready(Err(e)),
|
Some(Err(err)) => Ready(Err(err)),
|
||||||
None => Ready(Ok(())),
|
None => Ready(Ok(())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2022-xx-xx
|
||||||
|
- Minimum supported Rust version (MSRV) is now 1.49.
|
||||||
|
|
||||||
|
|
||||||
## 0.2.3 - 2021-10-19
|
## 0.2.3 - 2021-10-19
|
||||||
|
@@ -1,6 +1,25 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2022-xx-xx
|
||||||
|
|
||||||
|
|
||||||
|
## 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
|
## 2.5.0 - 2021-11-22
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-rt"
|
name = "actix-rt"
|
||||||
version = "2.5.0"
|
version = "2.7.0"
|
||||||
authors = [
|
authors = [
|
||||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||||
"Rob Ede <robjtede@icloud.com>",
|
"Rob Ede <robjtede@icloud.com>",
|
||||||
@@ -27,11 +27,12 @@ io-uring = ["tokio-uring"]
|
|||||||
actix-macros = { version = "0.2.3", optional = true }
|
actix-macros = { version = "0.2.3", optional = true }
|
||||||
|
|
||||||
futures-core = { version = "0.3", default-features = false }
|
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]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
tokio-uring = { version = "0.1", optional = true }
|
tokio-uring = { version = "0.3", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { version = "1.5.1", features = ["full"] }
|
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.
|
> Tokio-based single-threaded async runtime for the Actix ecosystem.
|
||||||
|
|
||||||
[](https://crates.io/crates/actix-rt)
|
[](https://crates.io/crates/actix-rt)
|
||||||
[](https://docs.rs/actix-rt/2.5.0)
|
[](https://docs.rs/actix-rt/2.7.0)
|
||||||
[](https://blog.rust-lang.org/2020/03/12/Rust-1.46.html)
|
[](https://blog.rust-lang.org/2020/03/12/Rust-1.46.html)
|
||||||

|

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

|

|
||||||
[](https://discord.gg/WghFtEH6Hb)
|
[](https://discord.gg/WghFtEH6Hb)
|
||||||
|
|
||||||
|
@@ -21,8 +21,8 @@ fn main() {
|
|||||||
let server =
|
let server =
|
||||||
Server::bind(&SocketAddr::from(([127, 0, 0, 1], 3000))).serve(make_service);
|
Server::bind(&SocketAddr::from(([127, 0, 0, 1], 3000))).serve(make_service);
|
||||||
|
|
||||||
if let Err(e) = server.await {
|
if let Err(err) = server.await {
|
||||||
eprintln!("server error: {}", e);
|
eprintln!("server error: {}", err);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -108,7 +108,6 @@ impl Arbiter {
|
|||||||
///
|
///
|
||||||
/// [tokio-runtime]: tokio::runtime::Runtime
|
/// [tokio-runtime]: tokio::runtime::Runtime
|
||||||
#[cfg(not(all(target_os = "linux", feature = "io-uring")))]
|
#[cfg(not(all(target_os = "linux", feature = "io-uring")))]
|
||||||
#[doc(hidden)]
|
|
||||||
pub fn with_tokio_rt<F>(runtime_factory: F) -> Arbiter
|
pub fn with_tokio_rt<F>(runtime_factory: F) -> Arbiter
|
||||||
where
|
where
|
||||||
F: Fn() -> tokio::runtime::Runtime + Send + 'static,
|
F: Fn() -> tokio::runtime::Runtime + Send + 'static,
|
||||||
|
@@ -46,7 +46,6 @@ impl System {
|
|||||||
/// Create a new System using the [Tokio Runtime](tokio-runtime) returned from a closure.
|
/// Create a new System using the [Tokio Runtime](tokio-runtime) returned from a closure.
|
||||||
///
|
///
|
||||||
/// [tokio-runtime]: tokio::runtime::Runtime
|
/// [tokio-runtime]: tokio::runtime::Runtime
|
||||||
#[doc(hidden)]
|
|
||||||
pub fn with_tokio_rt<F>(runtime_factory: F) -> SystemRunner
|
pub fn with_tokio_rt<F>(runtime_factory: F) -> SystemRunner
|
||||||
where
|
where
|
||||||
F: Fn() -> tokio::runtime::Runtime,
|
F: Fn() -> tokio::runtime::Runtime,
|
||||||
|
@@ -1,6 +1,39 @@
|
|||||||
# Changes
|
# 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
|
## 2.0.0-rc.1 - 2021-12-05
|
||||||
|
@@ -1,14 +1,17 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-server"
|
name = "actix-server"
|
||||||
version = "2.0.0-rc.1"
|
version = "2.1.1"
|
||||||
authors = [
|
authors = [
|
||||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||||
"fakeshadow <24548779@qq.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"
|
description = "General purpose TCP server built for the Actix ecosystem"
|
||||||
keywords = ["network", "framework", "async", "futures"]
|
keywords = ["network", "tcp", "server", "framework", "async"]
|
||||||
repository = "https://github.com/actix/actix-net.git"
|
|
||||||
categories = ["network-programming", "asynchronous"]
|
categories = ["network-programming", "asynchronous"]
|
||||||
|
homepage = "https://actix.rs"
|
||||||
|
repository = "https://github.com/actix/actix-net.git"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@@ -21,26 +24,27 @@ default = []
|
|||||||
io-uring = ["tokio-uring", "actix-rt/io-uring"]
|
io-uring = ["tokio-uring", "actix-rt/io-uring"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-rt = { version = "2.4.0", default-features = false }
|
actix-rt = { version = "2.7", default-features = false }
|
||||||
actix-service = "2.0.0"
|
actix-service = "2"
|
||||||
actix-utils = "3.0.0"
|
actix-utils = "3"
|
||||||
|
|
||||||
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
||||||
futures-util = { 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"] }
|
mio = { version = "0.8", features = ["os-poll", "net"] }
|
||||||
num_cpus = "1.13"
|
num_cpus = "1.13"
|
||||||
socket2 = "0.4.2"
|
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
|
# runtime for `io-uring` feature
|
||||||
tokio-uring = { version = "0.1", optional = true }
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
|
tokio-uring = { version = "0.3", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-codec = "0.4.0"
|
actix-codec = "0.5.0"
|
||||||
actix-rt = "2.4.0"
|
actix-rt = "2.6.0"
|
||||||
|
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
futures-util = { version = "0.3.7", default-features = false, features = ["sink", "async-await-macro"] }
|
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
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.1.1)
|
||||||
|
[](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
|
||||||
|

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

|
||||||
|
[](https://discord.gg/NWpN5mmg3x)
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
- [Library Documentation](https://docs.rs/actix-server)
|
||||||
|
- [Examples](/actix-server/examples)
|
95
actix-server/examples/file-reader.rs
Normal file
95
actix-server/examples/file-reader.rs
Normal 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(())
|
||||||
|
// }
|
@@ -22,16 +22,15 @@ use actix_server::Server;
|
|||||||
use actix_service::{fn_service, ServiceFactoryExt as _};
|
use actix_service::{fn_service, ServiceFactoryExt as _};
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use futures_util::future::ok;
|
use futures_util::future::ok;
|
||||||
use log::{error, info};
|
|
||||||
use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _};
|
use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _};
|
||||||
|
|
||||||
async fn run() -> io::Result<()> {
|
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 count = Arc::new(AtomicUsize::new(0));
|
||||||
|
|
||||||
let addr = ("127.0.0.1", 8080);
|
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
|
// 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
|
// 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
|
// more bytes to process
|
||||||
Ok(bytes_read) => {
|
Ok(bytes_read) => {
|
||||||
info!("[{}] read {} bytes", num, bytes_read);
|
tracing::info!("[{}] read {} bytes", num, bytes_read);
|
||||||
stream.write_all(&buf[size..]).await.unwrap();
|
stream.write_all(&buf[size..]).await.unwrap();
|
||||||
size += bytes_read;
|
size += bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
// stream error; bail from loop with error
|
// stream error; bail from loop with error
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("Stream Error: {:?}", err);
|
tracing::error!("Stream Error: {:?}", err);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,10 +74,10 @@ async fn run() -> io::Result<()> {
|
|||||||
Ok((buf.freeze(), size))
|
Ok((buf.freeze(), size))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map_err(|err| error!("Service Error: {:?}", err))
|
.map_err(|err| tracing::error!("Service Error: {:?}", err))
|
||||||
.and_then(move |(_, size)| {
|
.and_then(move |(_, size)| {
|
||||||
let num = num2.load(Ordering::SeqCst);
|
let num = num2.load(Ordering::SeqCst);
|
||||||
info!("[{}] total bytes read: {}", num, size);
|
tracing::info!("[{}] total bytes read: {}", num, size);
|
||||||
ok(size)
|
ok(size)
|
||||||
})
|
})
|
||||||
})?
|
})?
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
use std::{io, thread, time::Duration};
|
use std::{io, thread, time::Duration};
|
||||||
|
|
||||||
use actix_rt::time::Instant;
|
use actix_rt::time::Instant;
|
||||||
use log::{debug, error, info};
|
|
||||||
use mio::{Interest, Poll, Token as MioToken};
|
use mio::{Interest, Poll, Token as MioToken};
|
||||||
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
availability::Availability,
|
availability::Availability,
|
||||||
@@ -41,7 +41,7 @@ impl Accept {
|
|||||||
pub(crate) fn start(
|
pub(crate) fn start(
|
||||||
sockets: Vec<(usize, MioListener)>,
|
sockets: Vec<(usize, MioListener)>,
|
||||||
builder: &ServerBuilder,
|
builder: &ServerBuilder,
|
||||||
) -> io::Result<(WakerQueue, Vec<WorkerHandleServer>)> {
|
) -> io::Result<(WakerQueue, Vec<WorkerHandleServer>, thread::JoinHandle<()>)> {
|
||||||
let handle_server = ServerHandle::new(builder.cmd_tx.clone());
|
let handle_server = ServerHandle::new(builder.cmd_tx.clone());
|
||||||
|
|
||||||
// construct poll instance and its waker
|
// construct poll instance and its waker
|
||||||
@@ -73,12 +73,12 @@ impl Accept {
|
|||||||
handle_server,
|
handle_server,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
thread::Builder::new()
|
let accept_handle = thread::Builder::new()
|
||||||
.name("actix-server acceptor".to_owned())
|
.name("actix-server acceptor".to_owned())
|
||||||
.spawn(move || accept.poll_with(&mut sockets))
|
.spawn(move || accept.poll_with(&mut sockets))
|
||||||
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
|
.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(
|
fn new_with_sockets(
|
||||||
@@ -127,10 +127,10 @@ impl Accept {
|
|||||||
let mut events = mio::Events::with_capacity(256);
|
let mut events = mio::Events::with_capacity(256);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Err(e) = self.poll.poll(&mut events, self.timeout) {
|
if let Err(err) = self.poll.poll(&mut events, self.timeout) {
|
||||||
match e.kind() {
|
match err.kind() {
|
||||||
io::ErrorKind::Interrupted => {}
|
io::ErrorKind::Interrupted => {}
|
||||||
_ => panic!("Poll error: {}", e),
|
_ => panic!("Poll error: {}", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,15 +298,15 @@ impl Accept {
|
|||||||
fn register_logged(&self, info: &mut ServerSocketInfo) {
|
fn register_logged(&self, info: &mut ServerSocketInfo) {
|
||||||
match self.register(info) {
|
match self.register(info) {
|
||||||
Ok(_) => debug!("Resume accepting connections on {}", info.lst.local_addr()),
|
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) {
|
fn deregister_logged(&self, info: &mut ServerSocketInfo) {
|
||||||
match self.poll.registry().deregister(&mut info.lst) {
|
match self.poll.registry().deregister(&mut info.lst) {
|
||||||
Ok(_) => debug!("Paused accepting connections on {}", info.lst.local_addr()),
|
Ok(_) => debug!("Paused accepting connections on {}", info.lst.local_addr()),
|
||||||
Err(e) => {
|
Err(err) => {
|
||||||
error!("Can not deregister server socket {}", e)
|
error!("Can not deregister server socket {}", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -396,10 +396,10 @@ impl Accept {
|
|||||||
let conn = Conn { io, token };
|
let conn = Conn { io, token };
|
||||||
self.accept_one(conn);
|
self.accept_one(conn);
|
||||||
}
|
}
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => return,
|
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => return,
|
||||||
Err(ref e) if connection_error(e) => continue,
|
Err(ref err) if connection_error(err) => continue,
|
||||||
Err(e) => {
|
Err(err) => {
|
||||||
error!("Error accepting connection: {}", e);
|
error!("Error accepting connection: {}", err);
|
||||||
|
|
||||||
// deregister listener temporary
|
// deregister listener temporary
|
||||||
self.deregister_logged(info);
|
self.deregister_logged(info);
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
use std::{io, time::Duration};
|
use std::{io, time::Duration};
|
||||||
|
|
||||||
use actix_rt::net::TcpStream;
|
use actix_rt::net::TcpStream;
|
||||||
use log::{info, trace};
|
|
||||||
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
||||||
|
use tracing::{info, trace};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
server::ServerCommand,
|
server::ServerCommand,
|
||||||
service::{InternalServiceFactory, ServiceFactory, StreamNewService},
|
service::{InternalServiceFactory, ServerServiceFactory, StreamNewService},
|
||||||
socket::{
|
socket::{
|
||||||
create_mio_tcp_listener, MioListener, MioTcpListener, StdTcpListener, ToSocketAddrs,
|
create_mio_tcp_listener, MioListener, MioTcpListener, StdTcpListener, ToSocketAddrs,
|
||||||
},
|
},
|
||||||
@@ -140,10 +140,11 @@ impl ServerBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add new service to the server.
|
/// 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
|
where
|
||||||
F: ServiceFactory<TcpStream>,
|
F: ServerServiceFactory<TcpStream>,
|
||||||
U: ToSocketAddrs,
|
U: ToSocketAddrs,
|
||||||
|
N: AsRef<str>,
|
||||||
{
|
{
|
||||||
let sockets = bind_addr(addr, self.backlog)?;
|
let sockets = bind_addr(addr, self.backlog)?;
|
||||||
|
|
||||||
@@ -172,7 +173,7 @@ impl ServerBuilder {
|
|||||||
factory: F,
|
factory: F,
|
||||||
) -> io::Result<Self>
|
) -> io::Result<Self>
|
||||||
where
|
where
|
||||||
F: ServiceFactory<TcpStream>,
|
F: ServerServiceFactory<TcpStream>,
|
||||||
{
|
{
|
||||||
lst.set_nonblocking(true)?;
|
lst.set_nonblocking(true)?;
|
||||||
let addr = lst.local_addr()?;
|
let addr = lst.local_addr()?;
|
||||||
@@ -213,16 +214,16 @@ impl ServerBuilder {
|
|||||||
/// Add new unix domain service to the server.
|
/// 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>
|
pub fn bind_uds<F, U, N>(self, name: N, addr: U, factory: F) -> io::Result<Self>
|
||||||
where
|
where
|
||||||
F: ServiceFactory<actix_rt::net::UnixStream>,
|
F: ServerServiceFactory<actix_rt::net::UnixStream>,
|
||||||
N: AsRef<str>,
|
N: AsRef<str>,
|
||||||
U: AsRef<std::path::Path>,
|
U: AsRef<std::path::Path>,
|
||||||
{
|
{
|
||||||
// The path must not exist when we try to bind.
|
// The path must not exist when we try to bind.
|
||||||
// Try to remove it to avoid bind error.
|
// 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.
|
// NotFound is expected and not an issue. Anything else is.
|
||||||
if e.kind() != std::io::ErrorKind::NotFound {
|
if err.kind() != std::io::ErrorKind::NotFound {
|
||||||
return Err(e);
|
return Err(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +241,7 @@ impl ServerBuilder {
|
|||||||
factory: F,
|
factory: F,
|
||||||
) -> io::Result<Self>
|
) -> io::Result<Self>
|
||||||
where
|
where
|
||||||
F: ServiceFactory<actix_rt::net::UnixStream>,
|
F: ServerServiceFactory<actix_rt::net::UnixStream>,
|
||||||
{
|
{
|
||||||
use std::net::{IpAddr, Ipv4Addr};
|
use std::net::{IpAddr, Ipv4Addr};
|
||||||
lst.set_nonblocking(true)?;
|
lst.set_nonblocking(true)?;
|
||||||
@@ -263,22 +264,23 @@ pub(super) fn bind_addr<S: ToSocketAddrs>(
|
|||||||
addr: S,
|
addr: S,
|
||||||
backlog: u32,
|
backlog: u32,
|
||||||
) -> io::Result<Vec<MioTcpListener>> {
|
) -> io::Result<Vec<MioTcpListener>> {
|
||||||
let mut err = None;
|
let mut opt_err = None;
|
||||||
let mut success = false;
|
let mut success = false;
|
||||||
let mut sockets = Vec::new();
|
let mut sockets = Vec::new();
|
||||||
|
|
||||||
for addr in addr.to_socket_addrs()? {
|
for addr in addr.to_socket_addrs()? {
|
||||||
match create_mio_tcp_listener(addr, backlog) {
|
match create_mio_tcp_listener(addr, backlog) {
|
||||||
Ok(lst) => {
|
Ok(lst) => {
|
||||||
success = true;
|
success = true;
|
||||||
sockets.push(lst);
|
sockets.push(lst);
|
||||||
}
|
}
|
||||||
Err(e) => err = Some(e),
|
Err(err) => opt_err = Some(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if success {
|
if success {
|
||||||
Ok(sockets)
|
Ok(sockets)
|
||||||
} else if let Some(err) = err.take() {
|
} else if let Some(err) = opt_err.take() {
|
||||||
Err(err)
|
Err(err)
|
||||||
} else {
|
} else {
|
||||||
Err(io::Error::new(
|
Err(io::Error::new(
|
||||||
|
@@ -21,7 +21,7 @@ mod worker;
|
|||||||
pub use self::builder::ServerBuilder;
|
pub use self::builder::ServerBuilder;
|
||||||
pub use self::handle::ServerHandle;
|
pub use self::handle::ServerHandle;
|
||||||
pub use self::server::Server;
|
pub use self::server::Server;
|
||||||
pub use self::service::ServiceFactory;
|
pub use self::service::ServerServiceFactory;
|
||||||
pub use self::test_server::TestServer;
|
pub use self::test_server::TestServer;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@@ -3,14 +3,15 @@ use std::{
|
|||||||
io, mem,
|
io, mem,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
|
thread,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use actix_rt::{time::sleep, System};
|
use actix_rt::{time::sleep, System};
|
||||||
use futures_core::{future::BoxFuture, Stream};
|
use futures_core::{future::BoxFuture, Stream};
|
||||||
use futures_util::stream::StreamExt as _;
|
use futures_util::stream::StreamExt as _;
|
||||||
use log::{error, info};
|
|
||||||
use tokio::sync::{mpsc::UnboundedReceiver, oneshot};
|
use tokio::sync::{mpsc::UnboundedReceiver, oneshot};
|
||||||
|
use tracing::{error, info};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
accept::Accept,
|
accept::Accept,
|
||||||
@@ -158,6 +159,7 @@ impl Future for Server {
|
|||||||
|
|
||||||
pub struct ServerInner {
|
pub struct ServerInner {
|
||||||
worker_handles: Vec<WorkerHandleServer>,
|
worker_handles: Vec<WorkerHandleServer>,
|
||||||
|
accept_handle: Option<thread::JoinHandle<()>>,
|
||||||
worker_config: ServerWorkerConfig,
|
worker_config: ServerWorkerConfig,
|
||||||
services: Vec<Box<dyn InternalServiceFactory>>,
|
services: Vec<Box<dyn InternalServiceFactory>>,
|
||||||
waker_queue: WakerQueue,
|
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 {
|
let mux = ServerEventMultiplexer {
|
||||||
signal_fut: (builder.listen_os_signals).then(Signals::new),
|
signal_fut: (builder.listen_os_signals).then(Signals::new),
|
||||||
@@ -214,6 +216,7 @@ impl ServerInner {
|
|||||||
|
|
||||||
let server = ServerInner {
|
let server = ServerInner {
|
||||||
waker_queue,
|
waker_queue,
|
||||||
|
accept_handle: Some(accept_handle),
|
||||||
worker_handles,
|
worker_handles,
|
||||||
worker_config: builder.worker_config,
|
worker_config: builder.worker_config,
|
||||||
services: builder.factories,
|
services: builder.factories,
|
||||||
@@ -243,7 +246,8 @@ impl ServerInner {
|
|||||||
} => {
|
} => {
|
||||||
self.stopping = true;
|
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);
|
self.waker_queue.wake(WakerInterest::Stop);
|
||||||
|
|
||||||
// send stop signal to workers
|
// send stop signal to workers
|
||||||
@@ -258,6 +262,13 @@ impl ServerInner {
|
|||||||
let _ = join_all(workers_stop).await;
|
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 {
|
if let Some(tx) = completion {
|
||||||
let _ = tx.send(());
|
let _ = tx.send(());
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +1,21 @@
|
|||||||
use std::marker::PhantomData;
|
use std::{
|
||||||
use std::net::SocketAddr;
|
marker::PhantomData,
|
||||||
use std::task::{Context, Poll};
|
net::SocketAddr,
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
|
|
||||||
use actix_service::{Service, ServiceFactory as BaseServiceFactory};
|
use actix_service::{Service, ServiceFactory as BaseServiceFactory};
|
||||||
use actix_utils::future::{ready, Ready};
|
use actix_utils::future::{ready, Ready};
|
||||||
use futures_core::future::LocalBoxFuture;
|
use futures_core::future::LocalBoxFuture;
|
||||||
use log::error;
|
use tracing::error;
|
||||||
|
|
||||||
use crate::socket::{FromStream, MioStream};
|
use crate::{
|
||||||
use crate::worker::WorkerCounterGuard;
|
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 = ()>;
|
type Factory: BaseServiceFactory<Stream, Config = ()>;
|
||||||
|
|
||||||
fn create(&self) -> Self::Factory;
|
fn create(&self) -> Self::Factory;
|
||||||
@@ -72,15 +77,15 @@ where
|
|||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(err) => {
|
||||||
error!("Can not convert to an async tcp stream: {}", e);
|
error!("Can not convert to an async tcp stream: {}", err);
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct StreamNewService<F: ServiceFactory<Io>, Io: FromStream> {
|
pub(crate) struct StreamNewService<F: ServerServiceFactory<Io>, Io: FromStream> {
|
||||||
name: String,
|
name: String,
|
||||||
inner: F,
|
inner: F,
|
||||||
token: usize,
|
token: usize,
|
||||||
@@ -90,7 +95,7 @@ pub(crate) struct StreamNewService<F: ServiceFactory<Io>, Io: FromStream> {
|
|||||||
|
|
||||||
impl<F, Io> StreamNewService<F, Io>
|
impl<F, Io> StreamNewService<F, Io>
|
||||||
where
|
where
|
||||||
F: ServiceFactory<Io>,
|
F: ServerServiceFactory<Io>,
|
||||||
Io: FromStream + Send + 'static,
|
Io: FromStream + Send + 'static,
|
||||||
{
|
{
|
||||||
pub(crate) fn create(
|
pub(crate) fn create(
|
||||||
@@ -111,7 +116,7 @@ where
|
|||||||
|
|
||||||
impl<F, Io> InternalServiceFactory for StreamNewService<F, Io>
|
impl<F, Io> InternalServiceFactory for StreamNewService<F, Io>
|
||||||
where
|
where
|
||||||
F: ServiceFactory<Io>,
|
F: ServerServiceFactory<Io>,
|
||||||
Io: FromStream + Send + 'static,
|
Io: FromStream + Send + 'static,
|
||||||
{
|
{
|
||||||
fn name(&self, _: usize) -> &str {
|
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
|
where
|
||||||
F: Fn() -> T + Send + Clone + 'static,
|
F: Fn() -> T + Send + Clone + 'static,
|
||||||
T: BaseServiceFactory<I, Config = ()>,
|
T: BaseServiceFactory<I, Config = ()>,
|
||||||
|
@@ -5,7 +5,7 @@ use std::{
|
|||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
/// Types of process signals.
|
/// Types of process signals.
|
||||||
// #[allow(dead_code)]
|
// #[allow(dead_code)]
|
||||||
@@ -69,7 +69,7 @@ impl Signals {
|
|||||||
unix::signal(*kind)
|
unix::signal(*kind)
|
||||||
.map(|tokio_sig| (*sig, tokio_sig))
|
.map(|tokio_sig| (*sig, tokio_sig))
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
log::error!(
|
tracing::error!(
|
||||||
"Can not initialize stream handler for {:?} err: {}",
|
"Can not initialize stream handler for {:?} err: {}",
|
||||||
sig,
|
sig,
|
||||||
e
|
e
|
||||||
|
@@ -1,19 +1,18 @@
|
|||||||
pub(crate) use std::net::{
|
pub(crate) use std::net::{
|
||||||
SocketAddr as StdSocketAddr, TcpListener as StdTcpListener, ToSocketAddrs,
|
SocketAddr as StdSocketAddr, TcpListener as StdTcpListener, ToSocketAddrs,
|
||||||
};
|
};
|
||||||
|
use std::{fmt, io};
|
||||||
|
|
||||||
|
use actix_rt::net::TcpStream;
|
||||||
pub(crate) use mio::net::TcpListener as MioTcpListener;
|
pub(crate) use mio::net::TcpListener as MioTcpListener;
|
||||||
|
use mio::{event::Source, Interest, Registry, Token};
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub(crate) use {
|
pub(crate) use {
|
||||||
mio::net::UnixListener as MioUnixListener,
|
mio::net::UnixListener as MioUnixListener,
|
||||||
std::os::unix::net::UnixListener as StdUnixListener,
|
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 {
|
pub(crate) enum MioListener {
|
||||||
Tcp(MioTcpListener),
|
Tcp(MioTcpListener),
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
@@ -2,7 +2,7 @@ use std::{io, net, sync::mpsc, thread};
|
|||||||
|
|
||||||
use actix_rt::{net::TcpStream, System};
|
use actix_rt::{net::TcpStream, System};
|
||||||
|
|
||||||
use crate::{Server, ServerBuilder, ServerHandle, ServiceFactory};
|
use crate::{Server, ServerBuilder, ServerHandle, ServerServiceFactory};
|
||||||
|
|
||||||
/// A testing server.
|
/// A testing server.
|
||||||
///
|
///
|
||||||
@@ -16,7 +16,7 @@ use crate::{Server, ServerBuilder, ServerHandle, ServiceFactory};
|
|||||||
///
|
///
|
||||||
/// #[actix_rt::main]
|
/// #[actix_rt::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let srv = TestServer::with(|| fn_service(
|
/// let srv = TestServer::start(|| fn_service(
|
||||||
/// |sock| async move {
|
/// |sock| async move {
|
||||||
/// println!("New connection: {:?}", sock);
|
/// println!("New connection: {:?}", sock);
|
||||||
/// Ok::<_, ()>(())
|
/// Ok::<_, ()>(())
|
||||||
@@ -28,8 +28,8 @@ use crate::{Server, ServerBuilder, ServerHandle, ServiceFactory};
|
|||||||
/// ```
|
/// ```
|
||||||
pub struct TestServer;
|
pub struct TestServer;
|
||||||
|
|
||||||
/// Test server runtime
|
/// Test server handle.
|
||||||
pub struct TestServerRuntime {
|
pub struct TestServerHandle {
|
||||||
addr: net::SocketAddr,
|
addr: net::SocketAddr,
|
||||||
host: String,
|
host: String,
|
||||||
port: u16,
|
port: u16,
|
||||||
@@ -38,46 +38,26 @@ pub struct TestServerRuntime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TestServer {
|
impl TestServer {
|
||||||
/// Start new server with server builder.
|
/// Start new `TestServer` using application factory and default server config.
|
||||||
pub fn start<F>(mut factory: F) -> TestServerRuntime
|
pub fn start(factory: impl ServerServiceFactory<TcpStream>) -> TestServerHandle {
|
||||||
where
|
Self::start_with_builder(Server::build(), factory)
|
||||||
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 test server with application factory.
|
/// Start new `TestServer` using application factory and server builder.
|
||||||
pub fn with<F: ServiceFactory<TcpStream>>(factory: F) -> TestServerRuntime {
|
pub fn start_with_builder(
|
||||||
|
server_builder: ServerBuilder,
|
||||||
|
factory: impl ServerServiceFactory<TcpStream>,
|
||||||
|
) -> TestServerHandle {
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
// run server in separate thread
|
// run server in separate thread
|
||||||
let thread_handle = thread::spawn(move || {
|
let thread_handle = thread::spawn(move || {
|
||||||
let sys = System::new();
|
let lst = net::TcpListener::bind("127.0.0.1:0").unwrap();
|
||||||
let tcp = net::TcpListener::bind("127.0.0.1:0").unwrap();
|
let local_addr = lst.local_addr().unwrap();
|
||||||
let local_addr = tcp.local_addr().unwrap();
|
|
||||||
|
|
||||||
sys.block_on(async {
|
System::new().block_on(async {
|
||||||
let server = Server::build()
|
let server = server_builder
|
||||||
.listen("test", tcp, factory)
|
.listen("test", lst, factory)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.workers(1)
|
.workers(1)
|
||||||
.disable_signals()
|
.disable_signals()
|
||||||
@@ -93,7 +73,7 @@ impl TestServer {
|
|||||||
let host = format!("{}", addr.ip());
|
let host = format!("{}", addr.ip());
|
||||||
let port = addr.port();
|
let port = addr.port();
|
||||||
|
|
||||||
TestServerRuntime {
|
TestServerHandle {
|
||||||
addr,
|
addr,
|
||||||
host,
|
host,
|
||||||
port,
|
port,
|
||||||
@@ -107,17 +87,19 @@ impl TestServer {
|
|||||||
use socket2::{Domain, Protocol, Socket, Type};
|
use socket2::{Domain, Protocol, Socket, Type};
|
||||||
|
|
||||||
let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap();
|
let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap();
|
||||||
let socket =
|
let domain = Domain::for_address(addr);
|
||||||
Socket::new(Domain::for_address(addr), Type::STREAM, Some(Protocol::TCP)).unwrap();
|
let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP)).unwrap();
|
||||||
|
|
||||||
socket.set_reuse_address(true).unwrap();
|
socket.set_reuse_address(true).unwrap();
|
||||||
socket.set_nonblocking(true).unwrap();
|
socket.set_nonblocking(true).unwrap();
|
||||||
socket.bind(&addr.into()).unwrap();
|
socket.bind(&addr.into()).unwrap();
|
||||||
socket.listen(1024).unwrap();
|
socket.listen(1024).unwrap();
|
||||||
|
|
||||||
net::TcpListener::from(socket).local_addr().unwrap()
|
net::TcpListener::from(socket).local_addr().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestServerRuntime {
|
impl TestServerHandle {
|
||||||
/// Test server host.
|
/// Test server host.
|
||||||
pub fn host(&self) -> &str {
|
pub fn host(&self) -> &str {
|
||||||
&self.host
|
&self.host
|
||||||
@@ -140,12 +122,12 @@ impl TestServerRuntime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Connect to server, returning a Tokio `TcpStream`.
|
/// 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)?)
|
TcpStream::from_std(net::TcpStream::connect(self.addr)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TestServerRuntime {
|
impl Drop for TestServerHandle {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.stop()
|
self.stop()
|
||||||
}
|
}
|
||||||
@@ -158,8 +140,14 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn plain_tokio_runtime() {
|
async fn connect_in_tokio_runtime() {
|
||||||
let srv = TestServer::with(|| fn_service(|_sock| async move { Ok::<_, ()>(()) }));
|
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());
|
assert!(srv.connect().is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,11 +17,11 @@ use actix_rt::{
|
|||||||
Arbiter, ArbiterHandle, System,
|
Arbiter, ArbiterHandle, System,
|
||||||
};
|
};
|
||||||
use futures_core::{future::LocalBoxFuture, ready};
|
use futures_core::{future::LocalBoxFuture, ready};
|
||||||
use log::{error, info, trace};
|
|
||||||
use tokio::sync::{
|
use tokio::sync::{
|
||||||
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
|
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
|
||||||
oneshot,
|
oneshot,
|
||||||
};
|
};
|
||||||
|
use tracing::{error, info, trace};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
service::{BoxedServerService, InternalServiceFactory},
|
service::{BoxedServerService, InternalServiceFactory},
|
||||||
|
@@ -26,20 +26,54 @@ fn test_bind() {
|
|||||||
let srv = Server::build()
|
let srv = Server::build()
|
||||||
.workers(1)
|
.workers(1)
|
||||||
.disable_signals()
|
.disable_signals()
|
||||||
|
.shutdown_timeout(3600)
|
||||||
.bind("test", addr, move || {
|
.bind("test", addr, move || {
|
||||||
fn_service(|_| async { Ok::<_, ()>(()) })
|
fn_service(|_| async { Ok::<_, ()>(()) })
|
||||||
})?
|
})?
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
let _ = tx.send(srv.handle());
|
tx.send(srv.handle()).unwrap();
|
||||||
|
|
||||||
srv.await
|
srv.await
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let srv = rx.recv().unwrap();
|
let srv = rx.recv().unwrap();
|
||||||
|
|
||||||
thread::sleep(Duration::from_millis(500));
|
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);
|
let _ = srv.stop(true);
|
||||||
h.join().unwrap().unwrap();
|
h.join().unwrap().unwrap();
|
||||||
@@ -80,38 +114,6 @@ fn plain_tokio_runtime() {
|
|||||||
h.join().unwrap().unwrap();
|
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]
|
#[test]
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn test_start() {
|
fn test_start() {
|
||||||
@@ -252,6 +254,7 @@ async fn test_max_concurrent_connections() {
|
|||||||
h.join().unwrap().unwrap();
|
h.join().unwrap().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: race-y failures detected due to integer underflow when calling Counter::total
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_service_restart() {
|
async fn test_service_restart() {
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
73
actix-server/tests/testing_server.rs
Normal file
73
actix-server/tests/testing_server.rs
Normal 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();
|
||||||
|
}
|
@@ -1,6 +1,7 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2022-xx-xx
|
||||||
|
- Minimum supported Rust version (MSRV) is now 1.49.
|
||||||
|
|
||||||
|
|
||||||
## 2.0.2 - 2021-12-18
|
## 2.0.2 - 2021-12-18
|
||||||
|
@@ -97,7 +97,7 @@ where
|
|||||||
|
|
||||||
match this.fut.poll(cx) {
|
match this.fut.poll(cx) {
|
||||||
Poll::Ready(Ok(resp)) => Poll::Ready(Ok((this.f)(resp))),
|
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,
|
Poll::Pending => Poll::Pending,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,24 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2022-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
|
## 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
|
## 3.0.0-rc.2 - 2021-12-10
|
||||||
@@ -12,6 +26,7 @@
|
|||||||
|
|
||||||
[#429]: https://github.com/actix/actix-net/pull/429
|
[#429]: https://github.com/actix/actix-net/pull/429
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-rc.1 - 2021-11-29
|
## 3.0.0-rc.1 - 2021-11-29
|
||||||
### Added
|
### Added
|
||||||
- Derive `Debug` for `connect::Connection`. [#422]
|
- Derive `Debug` for `connect::Connection`. [#422]
|
||||||
@@ -117,7 +132,7 @@
|
|||||||
[#273]: https://github.com/actix/actix-net/pull/273
|
[#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]
|
- Depend on stable trust-dns packages. [#204]
|
||||||
|
|
||||||
[#204]: https://github.com/actix/actix-net/pull/204
|
[#204]: https://github.com/actix/actix-net/pull/204
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-tls"
|
name = "actix-tls"
|
||||||
version = "3.0.0"
|
version = "3.0.3"
|
||||||
authors = [
|
authors = [
|
||||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||||
"Rob Ede <robjtede@icloud.com>",
|
"Rob Ede <robjtede@icloud.com>",
|
||||||
@@ -42,16 +42,15 @@ native-tls = ["tokio-native-tls"]
|
|||||||
uri = ["http"]
|
uri = ["http"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-codec = "0.4.0"
|
actix-codec = "0.5.0"
|
||||||
actix-rt = { version = "2.2.0", default-features = false }
|
actix-rt = { version = "2.2.0", default-features = false }
|
||||||
actix-service = "2.0.0"
|
actix-service = "2.0.0"
|
||||||
actix-utils = "3.0.0"
|
actix-utils = "3.0.0"
|
||||||
|
|
||||||
derive_more = "0.99.5"
|
|
||||||
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pin-project-lite = "0.2.7"
|
pin-project-lite = "0.2.7"
|
||||||
tokio-util = { version = "0.6.3", default-features = false }
|
tokio-util = "0.7"
|
||||||
|
|
||||||
# uri
|
# uri
|
||||||
http = { version = "0.2.3", optional = true }
|
http = { version = "0.2.3", optional = true }
|
||||||
@@ -69,7 +68,7 @@ tokio-native-tls = { version = "0.3", optional = true }
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-rt = "2.2.0"
|
actix-rt = "2.2.0"
|
||||||
actix-server = "2.0.0-rc.1"
|
actix-server = "2.0.0"
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
futures-util = { version = "0.3.7", default-features = false, features = ["sink"] }
|
futures-util = { version = "0.3.7", default-features = false, features = ["sink"] }
|
||||||
|
@@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
|
error::Error,
|
||||||
|
fmt,
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
sync::atomic::{AtomicUsize, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
use actix_utils::counter::Counter;
|
use actix_utils::counter::Counter;
|
||||||
use derive_more::{Display, Error};
|
|
||||||
|
|
||||||
#[cfg(feature = "openssl")]
|
#[cfg(feature = "openssl")]
|
||||||
#[cfg_attr(docsrs, doc(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.
|
/// TLS handshake error, TLS timeout, or inner service error.
|
||||||
///
|
///
|
||||||
/// All TLS acceptors from this crate will return the `SvcErr` type parameter as [`Infallible`],
|
/// 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,
|
/// which can be cast to your own service type, inferred or otherwise, using [`into_service_error`].
|
||||||
/// using [`into_service_error`](Self::into_service_error).
|
///
|
||||||
#[derive(Debug, Display, Error)]
|
/// [`into_service_error`]: Self::into_service_error
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum TlsError<TlsErr, SvcErr> {
|
pub enum TlsError<TlsErr, SvcErr> {
|
||||||
/// TLS handshake has timed-out.
|
/// TLS handshake has timed-out.
|
||||||
#[display(fmt = "TLS handshake has timed-out")]
|
|
||||||
Timeout,
|
Timeout,
|
||||||
|
|
||||||
/// Wraps TLS service errors.
|
/// Wraps TLS service errors.
|
||||||
#[display(fmt = "TLS handshake error")]
|
|
||||||
Tls(TlsErr),
|
Tls(TlsErr),
|
||||||
|
|
||||||
/// Wraps service errors.
|
/// Wraps service errors.
|
||||||
#[display(fmt = "Service error")]
|
|
||||||
Service(SvcErr),
|
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> {
|
impl<TlsErr> TlsError<TlsErr, Infallible> {
|
||||||
/// Casts the infallible service error type returned from acceptors into caller's type.
|
/// Casts the infallible service error type returned from acceptors into caller's type.
|
||||||
///
|
///
|
||||||
|
@@ -20,11 +20,11 @@ use actix_utils::{
|
|||||||
counter::Counter,
|
counter::Counter,
|
||||||
future::{ready, Ready as FutReady},
|
future::{ready, Ready as FutReady},
|
||||||
};
|
};
|
||||||
use derive_more::{Deref, DerefMut, From};
|
|
||||||
use futures_core::future::LocalBoxFuture;
|
use futures_core::future::LocalBoxFuture;
|
||||||
use tokio_native_tls::{native_tls::Error, TlsAcceptor};
|
use tokio_native_tls::{native_tls::Error, TlsAcceptor};
|
||||||
|
|
||||||
use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER};
|
use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER};
|
||||||
|
use crate::impl_more;
|
||||||
|
|
||||||
pub mod reexports {
|
pub mod reexports {
|
||||||
//! Re-exports from `native-tls` that are useful for acceptors.
|
//! 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`].
|
/// 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>);
|
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> {
|
impl<IO: ActixStream> AsyncRead for TlsStream<IO> {
|
||||||
fn poll_read(
|
fn poll_read(
|
||||||
self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
|
@@ -21,11 +21,11 @@ use actix_utils::{
|
|||||||
counter::{Counter, CounterGuard},
|
counter::{Counter, CounterGuard},
|
||||||
future::{ready, Ready as FutReady},
|
future::{ready, Ready as FutReady},
|
||||||
};
|
};
|
||||||
use derive_more::{Deref, DerefMut, From};
|
|
||||||
use openssl::ssl::{Error, Ssl, SslAcceptor};
|
use openssl::ssl::{Error, Ssl, SslAcceptor};
|
||||||
use pin_project_lite::pin_project;
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER};
|
use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER};
|
||||||
|
use crate::impl_more;
|
||||||
|
|
||||||
pub mod reexports {
|
pub mod reexports {
|
||||||
//! Re-exports from `openssl` that are useful for acceptors.
|
//! 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`].
|
/// Wraps an `openssl` based async TLS stream in order to implement [`ActixStream`].
|
||||||
#[derive(Deref, DerefMut, From)]
|
|
||||||
pub struct TlsStream<IO>(tokio_openssl::SslStream<IO>);
|
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> {
|
impl<IO: ActixStream> AsyncRead for TlsStream<IO> {
|
||||||
fn poll_read(
|
fn poll_read(
|
||||||
self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
|
@@ -22,12 +22,12 @@ use actix_utils::{
|
|||||||
counter::{Counter, CounterGuard},
|
counter::{Counter, CounterGuard},
|
||||||
future::{ready, Ready as FutReady},
|
future::{ready, Ready as FutReady},
|
||||||
};
|
};
|
||||||
use derive_more::{Deref, DerefMut, From};
|
|
||||||
use pin_project_lite::pin_project;
|
use pin_project_lite::pin_project;
|
||||||
use tokio_rustls::rustls::ServerConfig;
|
use tokio_rustls::rustls::ServerConfig;
|
||||||
use tokio_rustls::{Accept, TlsAcceptor};
|
use tokio_rustls::{Accept, TlsAcceptor};
|
||||||
|
|
||||||
use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER};
|
use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER};
|
||||||
|
use crate::impl_more;
|
||||||
|
|
||||||
pub mod reexports {
|
pub mod reexports {
|
||||||
//! Re-exports from `rustls` that are useful for acceptors.
|
//! 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`].
|
/// 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>);
|
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> {
|
impl<IO: ActixStream> AsyncRead for TlsStream<IO> {
|
||||||
fn poll_read(
|
fn poll_read(
|
||||||
self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
|
@@ -1,20 +1,19 @@
|
|||||||
use derive_more::{Deref, DerefMut};
|
|
||||||
|
|
||||||
use super::Host;
|
use super::Host;
|
||||||
|
use crate::impl_more;
|
||||||
|
|
||||||
/// Wraps underlying I/O and the connection request that initiated it.
|
/// Wraps underlying I/O and the connection request that initiated it.
|
||||||
#[derive(Debug, Deref, DerefMut)]
|
#[derive(Debug)]
|
||||||
pub struct Connection<R, IO> {
|
pub struct Connection<R, IO> {
|
||||||
pub(crate) req: R,
|
pub(crate) req: R,
|
||||||
|
|
||||||
#[deref]
|
|
||||||
#[deref_mut]
|
|
||||||
pub(crate) io: IO,
|
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> {
|
impl<R, IO> Connection<R, IO> {
|
||||||
/// Construct new `Connection` from request and IO parts.
|
/// 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 }
|
Self { req, io }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,30 +1,38 @@
|
|||||||
use std::{error::Error, io};
|
use std::{error::Error, fmt, io};
|
||||||
|
|
||||||
use derive_more::Display;
|
|
||||||
|
|
||||||
/// Errors that can result from using a connector service.
|
/// Errors that can result from using a connector service.
|
||||||
#[derive(Debug, Display)]
|
#[derive(Debug)]
|
||||||
pub enum ConnectError {
|
pub enum ConnectError {
|
||||||
/// Failed to resolve the hostname
|
/// Failed to resolve the hostname.
|
||||||
#[display(fmt = "Failed resolving hostname")]
|
|
||||||
Resolver(Box<dyn std::error::Error>),
|
Resolver(Box<dyn std::error::Error>),
|
||||||
|
|
||||||
/// No DNS records
|
/// No DNS records.
|
||||||
#[display(fmt = "No DNS records found for the input")]
|
|
||||||
NoRecords,
|
NoRecords,
|
||||||
|
|
||||||
/// Invalid input
|
/// Invalid input.
|
||||||
InvalidInput,
|
InvalidInput,
|
||||||
|
|
||||||
/// Unresolved host name
|
/// Unresolved host name.
|
||||||
#[display(fmt = "Connector received `Connect` method with unresolved host")]
|
|
||||||
Unresolved,
|
Unresolved,
|
||||||
|
|
||||||
/// Connection IO error
|
/// Connection IO error.
|
||||||
#[display(fmt = "{}", _0)]
|
|
||||||
Io(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 {
|
impl Error for ConnectError {
|
||||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
match self {
|
match self {
|
||||||
|
@@ -27,25 +27,25 @@ pub trait Host: Unpin + 'static {
|
|||||||
|
|
||||||
impl Host for String {
|
impl Host for String {
|
||||||
fn hostname(&self) -> &str {
|
fn hostname(&self) -> &str {
|
||||||
self.split_once(':')
|
str_split_once(self, ':')
|
||||||
.map(|(hostname, _)| hostname)
|
.map(|(hostname, _)| hostname)
|
||||||
.unwrap_or(self)
|
.unwrap_or(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn port(&self) -> Option<u16> {
|
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 {
|
impl Host for &'static str {
|
||||||
fn hostname(&self) -> &str {
|
fn hostname(&self) -> &str {
|
||||||
self.split_once(':')
|
str_split_once(self, ':')
|
||||||
.map(|(hostname, _)| hostname)
|
.map(|(hostname, _)| hostname)
|
||||||
.unwrap_or(self)
|
.unwrap_or(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn port(&self) -> Option<u16> {
|
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);
|
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());
|
trace!("SSL Handshake success: {:?}", stream.hostname());
|
||||||
Poll::Ready(Ok(stream.replace_io(this.io.take().unwrap()).1))
|
Poll::Ready(Ok(stream.replace_io(this.io.take().unwrap()).1))
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(err) => {
|
||||||
trace!("SSL Handshake error: {:?}", e);
|
trace!("SSL Handshake error: {:?}", err);
|
||||||
Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, format!("{}", e))))
|
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) => {
|
Self::LookUp(fut, req) => {
|
||||||
let res = match ready!(Pin::new(fut).poll(cx)) {
|
let res = match ready!(Pin::new(fut).poll(cx)) {
|
||||||
Ok(Ok(res)) => Ok(res),
|
Ok(Ok(res)) => Ok(res),
|
||||||
Ok(Err(e)) => Err(ConnectError::Resolver(Box::new(e))),
|
Ok(Err(err)) => Err(ConnectError::Resolver(Box::new(err))),
|
||||||
Err(e) => Err(ConnectError::Io(e.into())),
|
Err(err) => Err(ConnectError::Io(err.into())),
|
||||||
};
|
};
|
||||||
|
|
||||||
let req = req.take().unwrap();
|
let req = req.take().unwrap();
|
||||||
|
@@ -79,7 +79,7 @@ pub enum TcpConnectorFut<R> {
|
|||||||
port: u16,
|
port: u16,
|
||||||
local_addr: Option<IpAddr>,
|
local_addr: Option<IpAddr>,
|
||||||
addrs: Option<VecDeque<SocketAddr>>,
|
addrs: Option<VecDeque<SocketAddr>>,
|
||||||
stream: ReusableBoxFuture<Result<TcpStream, io::Error>>,
|
stream: ReusableBoxFuture<'static, Result<TcpStream, io::Error>>,
|
||||||
},
|
},
|
||||||
|
|
||||||
Error(Option<ConnectError>),
|
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(feature = "connect")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "connect")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "connect")))]
|
||||||
pub mod connect;
|
pub mod connect;
|
||||||
|
|
||||||
|
mod impl_more;
|
||||||
|
@@ -94,7 +94,7 @@ fn rustls_connector(_cert: String, _key: String) -> ClientConfig {
|
|||||||
async fn accepts_connections() {
|
async fn accepts_connections() {
|
||||||
let (cert, key) = new_cert_and_key();
|
let (cert, key) = new_cert_and_key();
|
||||||
|
|
||||||
let srv = TestServer::with({
|
let srv = TestServer::start({
|
||||||
let cert = cert.clone();
|
let cert = cert.clone();
|
||||||
let key = key.clone();
|
let key = key.clone();
|
||||||
|
|
||||||
|
@@ -74,7 +74,7 @@ fn openssl_connector(cert: String, key: String) -> SslConnector {
|
|||||||
async fn accepts_connections() {
|
async fn accepts_connections() {
|
||||||
let (cert, key) = new_cert_and_key();
|
let (cert, key) = new_cert_and_key();
|
||||||
|
|
||||||
let srv = TestServer::with({
|
let srv = TestServer::start({
|
||||||
let cert = cert.clone();
|
let cert = cert.clone();
|
||||||
let key = key.clone();
|
let key = key.clone();
|
||||||
|
|
||||||
|
@@ -17,7 +17,7 @@ use actix_tls::connect::{ConnectError, ConnectInfo, Connection, Connector, Host}
|
|||||||
#[cfg(feature = "openssl")]
|
#[cfg(feature = "openssl")]
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_string() {
|
async fn test_string() {
|
||||||
let srv = TestServer::with(|| {
|
let srv = TestServer::start(|| {
|
||||||
fn_service(|io: TcpStream| async {
|
fn_service(|io: TcpStream| async {
|
||||||
let mut framed = Framed::new(io, BytesCodec);
|
let mut framed = Framed::new(io, BytesCodec);
|
||||||
framed.send(Bytes::from_static(b"test")).await?;
|
framed.send(Bytes::from_static(b"test")).await?;
|
||||||
@@ -34,7 +34,7 @@ async fn test_string() {
|
|||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "rustls")]
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_rustls_string() {
|
async fn test_rustls_string() {
|
||||||
let srv = TestServer::with(|| {
|
let srv = TestServer::start(|| {
|
||||||
fn_service(|io: TcpStream| async {
|
fn_service(|io: TcpStream| async {
|
||||||
let mut framed = Framed::new(io, BytesCodec);
|
let mut framed = Framed::new(io, BytesCodec);
|
||||||
framed.send(Bytes::from_static(b"test")).await?;
|
framed.send(Bytes::from_static(b"test")).await?;
|
||||||
@@ -50,7 +50,7 @@ async fn test_rustls_string() {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_static_str() {
|
async fn test_static_str() {
|
||||||
let srv = TestServer::with(|| {
|
let srv = TestServer::start(|| {
|
||||||
fn_service(|io: TcpStream| async {
|
fn_service(|io: TcpStream| async {
|
||||||
let mut framed = Framed::new(io, BytesCodec);
|
let mut framed = Framed::new(io, BytesCodec);
|
||||||
framed.send(Bytes::from_static(b"test")).await?;
|
framed.send(Bytes::from_static(b"test")).await?;
|
||||||
@@ -81,7 +81,7 @@ async fn service_factory() {
|
|||||||
Connector::default()
|
Connector::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
let srv = TestServer::with(|| {
|
let srv = TestServer::start(|| {
|
||||||
fn_service(|io: TcpStream| async {
|
fn_service(|io: TcpStream| async {
|
||||||
let mut framed = Framed::new(io, BytesCodec);
|
let mut framed = Framed::new(io, BytesCodec);
|
||||||
framed.send(Bytes::from_static(b"test")).await?;
|
framed.send(Bytes::from_static(b"test")).await?;
|
||||||
@@ -101,7 +101,7 @@ async fn service_factory() {
|
|||||||
async fn test_openssl_uri() {
|
async fn test_openssl_uri() {
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
let srv = TestServer::with(|| {
|
let srv = TestServer::start(|| {
|
||||||
fn_service(|io: TcpStream| async {
|
fn_service(|io: TcpStream| async {
|
||||||
let mut framed = Framed::new(io, BytesCodec);
|
let mut framed = Framed::new(io, BytesCodec);
|
||||||
framed.send(Bytes::from_static(b"test")).await?;
|
framed.send(Bytes::from_static(b"test")).await?;
|
||||||
@@ -120,7 +120,7 @@ async fn test_openssl_uri() {
|
|||||||
async fn test_rustls_uri() {
|
async fn test_rustls_uri() {
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
let srv = TestServer::with(|| {
|
let srv = TestServer::start(|| {
|
||||||
fn_service(|io: TcpStream| async {
|
fn_service(|io: TcpStream| async {
|
||||||
let mut framed = Framed::new(io, BytesCodec);
|
let mut framed = Framed::new(io, BytesCodec);
|
||||||
framed.send(Bytes::from_static(b"test")).await?;
|
framed.send(Bytes::from_static(b"test")).await?;
|
||||||
@@ -136,7 +136,7 @@ async fn test_rustls_uri() {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_local_addr() {
|
async fn test_local_addr() {
|
||||||
let srv = TestServer::with(|| {
|
let srv = TestServer::start(|| {
|
||||||
fn_service(|io: TcpStream| async {
|
fn_service(|io: TcpStream| async {
|
||||||
let mut framed = Framed::new(io, BytesCodec);
|
let mut framed = Framed::new(io, BytesCodec);
|
||||||
framed.send(Bytes::from_static(b"test")).await?;
|
framed.send(Bytes::from_static(b"test")).await?;
|
||||||
|
@@ -53,7 +53,7 @@ async fn custom_resolver_connect() {
|
|||||||
use trust_dns_resolver::TokioAsyncResolver;
|
use trust_dns_resolver::TokioAsyncResolver;
|
||||||
|
|
||||||
let srv =
|
let srv =
|
||||||
TestServer::with(|| fn_service(|_io: TcpStream| async { Ok::<_, io::Error>(()) }));
|
TestServer::start(|| fn_service(|_io: TcpStream| async { Ok::<_, io::Error>(()) }));
|
||||||
|
|
||||||
struct MyResolver {
|
struct MyResolver {
|
||||||
trust_dns: TokioAsyncResolver,
|
trust_dns: TokioAsyncResolver,
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
# Changes
|
# 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
|
- Initial release
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2022-xx-xx
|
||||||
|
- Minimum supported Rust version (MSRV) is now 1.49.
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0 - 2021-04-16
|
## 3.0.0 - 2021-04-16
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2022-xx-xx
|
||||||
|
- Minimum supported Rust version (MSRV) is now 1.49.
|
||||||
|
|
||||||
|
|
||||||
## 1.0.0 - 2020-12-31
|
## 1.0.0 - 2020-12-31
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2022-xx-xx
|
||||||
|
- Minimum supported Rust version (MSRV) is now 1.49.
|
||||||
|
|
||||||
|
|
||||||
## 0.1.2 - 2021-04-01
|
## 0.1.2 - 2021-04-01
|
||||||
|
@@ -18,4 +18,4 @@ futures-util = { version = "0.3.7", default-features = false }
|
|||||||
local-waker = "0.1"
|
local-waker = "0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { version = "1.5.1", features = ["rt", "macros"] }
|
tokio = { version = "1.13.1", features = ["rt", "macros"] }
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2022-xx-xx
|
||||||
|
- Minimum supported Rust version (MSRV) is now 1.49.
|
||||||
|
|
||||||
|
|
||||||
## 0.1.2 - 2021-12-18
|
## 0.1.2 - 2021-12-18
|
||||||
|
Reference in New Issue
Block a user