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

Compare commits

..

12 Commits

Author SHA1 Message Date
Rob Ede
70f59f46ef add no-op SSL TLV 2023-09-17 21:53:51 +01:00
Rob Ede
21c31ad63d add alpn and authority TLVs 2023-09-17 21:34:39 +01:00
Rob Ede
d336fb34ce add some typed TLVs 2023-09-17 21:34:39 +01:00
Rob Ede
69d9afd39e add Tlv trait 2023-09-17 21:34:39 +01:00
Rob Ede
b9877392ab PoC proxy protocol stream wrapper 2023-09-17 21:34:38 +01:00
Rob Ede
4a7f2c95af chore: remove dates from changelogs 2023-09-17 20:25:58 +01:00
Rob Ede
c69b8e9ade ci: move coverage to own workflow 2023-09-17 20:11:05 +01:00
Rob Ede
9f59093adc chore(local-channel): prepare release 0.1.4 2023-09-17 19:32:01 +01:00
Paolo Barbolini
bfeb4cd9e7 local-channel: drop futures-util by using future::poll_fn from std (#490) 2023-09-17 11:45:55 +00:00
Rob Ede
14272a1762 chore: force secure rustls-webpki 2023-08-29 18:45:11 +01:00
Rob Ede
7e043048a0 chore(actix-tls): prepare release 3.1.1 2023-08-29 18:41:48 +01:00
Rob Ede
45a7dcba90 chore(tls): fix min rustls version 2023-08-29 18:40:55 +01:00
27 changed files with 1223 additions and 180 deletions

View File

@@ -103,28 +103,6 @@ jobs:
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@v3
- name: Install Rust (nightly)
uses: actions-rust-lang/setup-rust-toolchain@v1
with: { toolchain: nightly }
- name: Install cargo-tarpaulin
uses: taiki-e/install-action@v1
with: { tool: cargo-tarpaulin }
- name: Generate coverage file
if: github.ref == 'refs/heads/master'
run: cargo tarpaulin --out Xml --verbose
- name: Upload to Codecov
if: github.ref == 'refs/heads/master'
uses: codecov/codecov-action@v3
with: { files: cobertura.xml }
minimal-versions:
name: minimal versions
runs-on: ubuntu-latest
@@ -133,11 +111,13 @@ jobs:
- name: Install Rust (nightly)
uses: actions-rust-lang/setup-rust-toolchain@v1
with: { toolchain: nightly }
with:
toolchain: nightly
- name: Install cargo-hack & cargo-minimal-versions
uses: taiki-e/install-action@v1
with: { tool: 'cargo-hack,cargo-minimal-versions' }
with:
tool: cargo-hack,cargo-minimal-versions
- name: Check With Minimal Versions
run: cargo minimal-versions check

37
.github/workflows/coverage.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Coverage
on:
push:
branches: [master]
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
with:
components: llvm-tools-preview
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@v2.18.9
with:
tool: cargo-llvm-cov
- name: Generate code coverage
run: cargo llvm-cov --workspace --all-features --codecov --output-path codecov.json
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3.1.4
with:
files: codecov.json
fail_ci_if_error: true

View File

@@ -2,6 +2,7 @@
members = [
"actix-codec",
"actix-macros",
"actix-proxy-protocol",
"actix-rt",
"actix-server",
"actix-service",
@@ -22,6 +23,7 @@ rust-version = "1.65"
[patch.crates-io]
actix-codec = { path = "actix-codec" }
actix-macros = { path = "actix-macros" }
actix-proxy-protocol = { path = "actix-proxy-protocol" }
actix-rt = { path = "actix-rt" }
actix-server = { path = "actix-server" }
actix-service = { path = "actix-service" }

View File

@@ -1,27 +1,27 @@
# Changes
## Unreleased - 2023-xx-xx
## Unreleased
- Minimum supported Rust version (MSRV) is now 1.65.
## 0.5.1 - 2022-03-15
## 0.5.1
- Logs emitted now use the `tracing` crate with `log` compatibility. [#451]
- Minimum supported Rust version (MSRV) is now 1.49.
[#451]: https://github.com/actix/actix-net/pull/451
## 0.5.0 - 2022-02-15
## 0.5.0
- Updated `tokio-util` dependency to `0.7.0`. [#446]
[#446]: https://github.com/actix/actix-net/pull/446
## 0.4.2 - 2021-12-31
## 0.4.2
- No significant changes since `0.4.1`.
## 0.4.1 - 2021-11-05
## 0.4.1
- Added `LinesCodec.` [#338]
- `Framed::poll_ready` flushes when the buffer is full. [#409]
@@ -29,11 +29,11 @@
[#338]: https://github.com/actix/actix-net/pull/338
[#409]: https://github.com/actix/actix-net/pull/409
## 0.4.0 - 2021-04-20
## 0.4.0
- No significant changes since v0.4.0-beta.1.
## 0.4.0-beta.1 - 2020-12-28
## 0.4.0-beta.1
- Replace `pin-project` with `pin-project-lite`. [#237]
- Upgrade `tokio` dependency to `1`. [#237]
@@ -42,15 +42,15 @@
[#237]: https://github.com/actix/actix-net/pull/237
## 0.3.0 - 2020-08-23
## 0.3.0
- No changes from beta 2.
## 0.3.0-beta.2 - 2020-08-19
## 0.3.0-beta.2
- Remove unused type parameter from `Framed::replace_codec`.
## 0.3.0-beta.1 - 2020-08-19
## 0.3.0-beta.1
- Use `.advance()` instead of `.split_to()`.
- Upgrade `tokio-util` to `0.3`.
@@ -60,7 +60,7 @@
- Add method on `Framed` to get a pinned reference to the underlying I/O.
- Add method on `Framed` check emptiness of read buffer.
## 0.2.0 - 2019-12-10
## 0.2.0
- Use specific futures dependencies.
@@ -77,14 +77,14 @@
- Migrated to `std::future`.
## 0.1.2 - 2019-03-27
## 0.1.2
- Added `Framed::map_io()` method.
## 0.1.1 - 2019-03-06
## 0.1.1
- Added `FramedParts::with_read_buffer()` method.
## 0.1.0 - 2018-12-09
## 0.1.0
- Move codec to separate crate.

View File

@@ -7,12 +7,17 @@ authors = [
"Rob Ede <robjtede@icloud.com>",
]
description = "Macros for Actix system and runtime"
repository = "https://github.com/actix/actix-net.git"
repository = "https://github.com/actix/actix-net"
categories = ["network-programming", "asynchronous"]
license = "MIT OR Apache-2.0"
license.workspace = true
edition.workspace = true
rust-version.workspace = true
[package.metadata.cargo-machete]
ignored = [
"proc_macro2", # specified for minimal versions compat
]
[lib]
proc-macro = true
@@ -20,6 +25,9 @@ proc-macro = true
quote = "1"
syn = { version = "2", features = ["full"] }
# minimal versions compat
proc-macro2 = "1.0.60"
[dev-dependencies]
actix-rt = "2"

View File

@@ -0,0 +1,7 @@
# Changes
## Unreleased - 2022-xx-xx
## 0.0.1 - 2022-xx-xx
- delete me

41
actix-proxy-protocol/Cargo.toml Executable file
View File

@@ -0,0 +1,41 @@
[package]
name = "actix-proxy-protocol"
version = "0.0.1"
authors = [
"Rob Ede <robjtede@icloud.com>",
]
description = "PROXY protocol utilities"
keywords = ["proxy", "protocol", "network", "haproxy", "tcp"]
categories = ["network-programming", "asynchronous"]
homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-net"
license.workspace = true
edition.workspace = true
rust-version.workspace = true
[dependencies]
actix-service = "2"
actix-utils = "3"
arrayvec = "0.7"
bitflags = "2"
crc32fast = "1"
futures-core = { version = "0.3.17", default-features = false, features = ["std"] }
futures-util = { version = "0.3.17", default-features = false, features = ["std"] }
itoa = "1"
smallvec = "1"
tokio = { version = "1.13.1", features = ["sync", "io-util"] }
tracing = { version = "0.1.30", default-features = false, features = ["log"] }
[dev-dependencies]
actix-codec = "0.5"
actix-rt = "2.6"
actix-server = "2"
bytes = "1"
const-str = "0.5"
env_logger = "0.9"
futures-util = { version = "0.3.7", default-features = false, features = ["sink", "async-await-macro"] }
once_cell = "1"
pretty_assertions = "1"
tokio = { version = "1.13.1", features = ["io-util", "rt-multi-thread", "macros", "fs"] }

View File

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

View File

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

View File

@@ -0,0 +1,17 @@
# actix-proxy-protocol
> Implementation of the [PROXY protocol].
[![crates.io](https://img.shields.io/crates/v/actix-proxy-protocol?label=latest)](https://crates.io/crates/actix-proxy-protocol)
[![Documentation](https://docs.rs/actix-proxy-protocol/badge.svg?version=0.1.0)](https://docs.rs/actix-proxy-protocol/0.1.0)
[![Version](https://img.shields.io/badge/rustc-1.52+-ab6000.svg)](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
![License](https://img.shields.io/crates/l/actix-proxy-protocol.svg)
[![Dependency Status](https://deps.rs/crate/actix-proxy-protocol/0.1.0/status.svg)](https://deps.rs/crate/actix-proxy-protocol/0.1.0)
![Downloads](https://img.shields.io/crates/d/actix-proxy-protocol.svg)
[![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/NWpN5mmg3x)
## Resources
- [Examples](./examples)
[proxy protocol]: https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt

View File

@@ -0,0 +1,113 @@
//! Adds PROXY protocol v1 prelude to connections.
#![allow(unused)]
use std::{
io, mem,
net::{IpAddr, Ipv4Addr, SocketAddr},
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
};
use actix_proxy_protocol::{tlv, v1, v2, AddressFamily, Command, TransportProtocol};
use actix_rt::net::TcpStream;
use actix_server::Server;
use actix_service::{fn_service, ServiceFactoryExt as _};
use bytes::BytesMut;
use const_str::concat_bytes;
use once_cell::sync::Lazy;
use tokio::io::{copy_bidirectional, AsyncReadExt as _, AsyncWriteExt as _};
static UPSTREAM: Lazy<SocketAddr> = Lazy::new(|| SocketAddr::from(([127, 0, 0, 1], 8080)));
/*
NOTES:
108 byte buffer on receiver side is enough for any PROXY header
after PROXY, receive until CRLF, *then* decode parts
TLV = type-length-value
TO DO:
handle UNKNOWN transport
v2 UNSPEC mode
AF_UNIX socket
*/
fn extend_with_ip_bytes(buf: &mut Vec<u8>, ip: IpAddr) {
match ip {
IpAddr::V4(ip) => buf.extend_from_slice(&ip.octets()),
IpAddr::V6(ip) => buf.extend_from_slice(&ip.octets()),
}
}
async fn wrap_with_proxy_protocol_v1(mut stream: TcpStream) -> io::Result<()> {
let mut upstream = TcpStream::connect(("127.0.0.1", 8080)).await?;
tracing::info!(
"PROXYv1 {} -> {}",
stream.peer_addr().unwrap(),
UPSTREAM.to_string()
);
let proxy_header = v1::Header::new(
AddressFamily::Inet,
SocketAddr::from(([127, 0, 0, 1], 8081)),
*UPSTREAM,
);
proxy_header.write_to_tokio(&mut upstream).await?;
let (_bytes_read, _bytes_written) = copy_bidirectional(&mut stream, &mut upstream).await?;
Ok(())
}
async fn wrap_with_proxy_protocol_v2(mut stream: TcpStream) -> io::Result<()> {
let mut upstream = TcpStream::connect(("127.0.0.1", 8080)).await?;
tracing::info!(
"PROXYv2 {} -> {}",
stream.peer_addr().unwrap(),
UPSTREAM.to_string()
);
let mut proxy_header = v2::Header::new_tcp_ipv4_proxy(([127, 0, 0, 1], 8082), *UPSTREAM);
proxy_header.add_typed_tlv(tlv::UniqueId::new("4269")); // UNIQUE_ID
proxy_header.add_typed_tlv(tlv::Noop::new("NOOP m8")); // NOOP
proxy_header.add_typed_tlv(tlv::Authority::new("localhost")); // NOOP
proxy_header.add_typed_tlv(tlv::Alpn::new("http/1.1")); // NOOP
proxy_header.add_crc23c_checksum();
proxy_header.write_to_tokio(&mut upstream).await?;
let (_bytes_read, _bytes_written) = copy_bidirectional(&mut stream, &mut upstream).await?;
Ok(())
}
fn start_server() -> io::Result<Server> {
let addr = ("127.0.0.1", 8082);
tracing::info!("starting proxy server on port: {}", &addr.0);
tracing::info!("proxying to 127.0.0.1:8080");
Ok(Server::build()
.bind("proxy-protocol-v1", ("127.0.0.1", 8081), move || {
fn_service(wrap_with_proxy_protocol_v1)
.map_err(|err| tracing::error!("service error: {:?}", err))
})?
.bind("proxy-protocol-v2", addr, move || {
fn_service(wrap_with_proxy_protocol_v2)
.map_err(|err| tracing::error!("service error: {:?}", err))
})?
.workers(2)
.run())
}
#[tokio::main]
async fn main() -> io::Result<()> {
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info"));
start_server()?.await?;
Ok(())
}

View File

@@ -0,0 +1,168 @@
//! PROXY protocol.
#![deny(rust_2018_idioms, nonstandard_style)]
#![warn(future_incompatible)]
// #![warn(missing_docs)]
#![allow(unused)]
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
use std::{
convert::TryFrom as _,
fmt, io,
net::{IpAddr, SocketAddr},
};
use arrayvec::{ArrayString, ArrayVec};
use tokio::io::{AsyncWrite, AsyncWriteExt as _};
pub mod tlv;
pub mod v1;
pub mod v2;
/// PROXY Protocol Version.
#[derive(Debug, Clone, Copy)]
enum Version {
/// Human-readable header format (Version 1)
V1,
/// Binary header format (Version 2)
V2,
}
impl Version {
const fn signature(&self) -> &'static [u8] {
match self {
Version::V1 => v1::SIGNATURE.as_bytes(),
Version::V2 => v2::SIGNATURE.as_slice(),
}
}
const fn v2_hi(&self) -> u8 {
(match self {
Version::V1 => panic!("v1 not supported in PROXY v2"),
Version::V2 => 0x2,
}) << 4
}
}
/// Command
///
/// other values are unassigned and must not be emitted by senders. Receivers
/// must drop connections presenting unexpected values here.
#[derive(Debug, Clone, Copy)]
pub enum Command {
/// \x0 : LOCAL : the connection was established on purpose by the proxy
/// without being relayed. The connection endpoints are the sender and the
/// receiver. Such connections exist when the proxy sends health-checks to the
/// server. The receiver must accept this connection as valid and must use the
/// real connection endpoints and discard the protocol block including the
/// family which is ignored.
Local,
/// \x1 : PROXY : the connection was established on behalf of another node,
/// and reflects the original connection endpoints. The receiver must then use
/// the information provided in the protocol block to get original the address.
Proxy,
}
impl Command {
const fn v2_lo(&self) -> u8 {
match self {
Command::Local => 0x0,
Command::Proxy => 0x1,
}
}
}
/// Address Family.
///
/// maps to the original socket family without necessarily
/// matching the values internally used by the system.
///
/// other values are unspecified and must not be emitted in version 2 of this
/// protocol and must be rejected as invalid by receivers.
#[derive(Debug, Clone, Copy)]
pub enum AddressFamily {
/// 0x0 : AF_UNSPEC : the connection is forwarded for an unknown, unspecified
/// or unsupported protocol. The sender should use this family when sending
/// LOCAL commands or when dealing with unsupported protocol families. The
/// receiver is free to accept the connection anyway and use the real endpoint
/// addresses or to reject it. The receiver should ignore address information.
Unspecified,
/// 0x1 : AF_INET : the forwarded connection uses the AF_INET address family
/// (IPv4). The addresses are exactly 4 bytes each in network byte order,
/// followed by transport protocol information (typically ports).
Inet,
/// 0x2 : AF_INET6 : the forwarded connection uses the AF_INET6 address family
/// (IPv6). The addresses are exactly 16 bytes each in network byte order,
/// followed by transport protocol information (typically ports).
Inet6,
/// 0x3 : AF_UNIX : the forwarded connection uses the AF_UNIX address family
/// (UNIX). The addresses are exactly 108 bytes each.
Unix,
}
impl AddressFamily {
fn v1_str(&self) -> &'static str {
match self {
AddressFamily::Inet => "TCP4",
AddressFamily::Inet6 => "TCP6",
af => panic!("{:?} is not supported in PROXY v1", af),
}
}
const fn v2_hi(&self) -> u8 {
(match self {
AddressFamily::Unspecified => 0x0,
AddressFamily::Inet => 0x1,
AddressFamily::Inet6 => 0x2,
AddressFamily::Unix => 0x3,
}) << 4
}
}
/// Transport Protocol.
///
/// other values are unspecified and must not be emitted in version 2 of this
/// protocol and must be rejected as invalid by receivers.
#[derive(Debug, Clone, Copy)]
pub enum TransportProtocol {
/// 0x0 : UNSPEC : the connection is forwarded for an unknown, unspecified
/// or unsupported protocol. The sender should use this family when sending
/// LOCAL commands or when dealing with unsupported protocol families. The
/// receiver is free to accept the connection anyway and use the real endpoint
/// addresses or to reject it. The receiver should ignore address information.
Unspecified,
/// 0x1 : STREAM : the forwarded connection uses a SOCK_STREAM protocol (eg:
/// TCP or UNIX_STREAM). When used with AF_INET/AF_INET6 (TCP), the addresses
/// are followed by the source and destination ports represented on 2 bytes
/// each in network byte order.
Stream,
/// 0x2 : DGRAM : the forwarded connection uses a SOCK_DGRAM protocol (eg:
/// UDP or UNIX_DGRAM). When used with AF_INET/AF_INET6 (UDP), the addresses
/// are followed by the source and destination ports represented on 2 bytes
/// each in network byte order.
Datagram,
}
impl TransportProtocol {
const fn v2_lo(&self) -> u8 {
match self {
TransportProtocol::Unspecified => 0x0,
TransportProtocol::Stream => 0x1,
TransportProtocol::Datagram => 0x2,
}
}
}
#[derive(Debug)]
enum ProxyProtocolHeader {
V1(v1::Header),
V2(v2::Header),
}

View File

@@ -0,0 +1,292 @@
use std::{borrow::Cow, convert::TryFrom, str};
const PP2_TYPE_ALPN: u8 = 0x01; // done
const PP2_TYPE_AUTHORITY: u8 = 0x02; // done
const PP2_TYPE_CRC32C: u8 = 0x03; // done
const PP2_TYPE_NOOP: u8 = 0x04; // done
const PP2_TYPE_UNIQUE_ID: u8 = 0x05; // done
const PP2_TYPE_SSL: u8 = 0x20;
const PP2_SUBTYPE_SSL_VERSION: u8 = 0x21;
const PP2_SUBTYPE_SSL_CN: u8 = 0x22;
const PP2_SUBTYPE_SSL_CIPHER: u8 = 0x23;
const PP2_SUBTYPE_SSL_SIG_ALG: u8 = 0x24;
const PP2_SUBTYPE_SSL_KEY_ALG: u8 = 0x25;
const PP2_TYPE_NETNS: u8 = 0x30;
pub trait Tlv: Sized {
const TYPE: u8;
fn try_from_value(value: &[u8]) -> Option<Self>;
fn value_bytes(&self) -> Cow<'_, [u8]>;
fn try_from_parts(typ: u8, value: &[u8]) -> Option<Self> {
if typ != Self::TYPE {
return None;
}
Self::try_from_value(value)
}
}
/// Application-Layer Protocol Negotiation (ALPN). It is a byte sequence defining
/// the upper layer protocol in use over the connection. The most common use case
/// will be to pass the exact copy of the ALPN extension of the Transport Layer
/// Security (TLS) protocol as defined by RFC7301 [9].
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Alpn {
alpn: Vec<u8>,
}
impl Alpn {
///
///
/// # Panics
/// Panics if `alpn` is empty (i.e., has length of 0).
pub fn new(alpn: impl Into<Vec<u8>>) -> Self {
let alpn = alpn.into();
assert!(!alpn.is_empty(), "ALPN TLV value cannot be empty");
Self { alpn }
}
}
impl Tlv for Alpn {
const TYPE: u8 = PP2_TYPE_ALPN;
fn try_from_value(value: &[u8]) -> Option<Self> {
Some(Self {
alpn: value.to_owned(),
})
}
fn value_bytes(&self) -> Cow<'_, [u8]> {
Cow::Borrowed(&self.alpn)
}
}
/// Contains the host name value passed by the client, as an UTF8-encoded string.
/// In case of TLS being used on the client connection, this is the exact copy of
/// the "server_name" extension as defined by RFC3546 [10], section 3.1, often
/// referred to as "SNI". There are probably other situations where an authority
/// can be mentioned on a connection without TLS being involved at all.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Authority {
authority: String,
}
impl Authority {
/// A UTF-8
///
/// # Panics
/// Panics if `authority` is an empty string.
pub fn new(authority: impl Into<String>) -> Self {
let authority = authority.into();
assert!(!authority.is_empty(), "Authority TLV value cannot be empty");
Self { authority }
}
}
impl Tlv for Authority {
const TYPE: u8 = PP2_TYPE_AUTHORITY;
fn try_from_value(value: &[u8]) -> Option<Self> {
Some(Self {
authority: str::from_utf8(value).ok()?.to_owned(),
})
}
fn value_bytes(&self) -> Cow<'_, [u8]> {
Cow::Borrowed(self.authority.as_bytes())
}
}
/// The value of the type PP2_TYPE_CRC32C is a 32-bit number storing the CRC32c
/// checksum of the PROXY protocol header.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Crc32c {
pub(crate) checksum: u32,
}
impl Tlv for Crc32c {
const TYPE: u8 = PP2_TYPE_CRC32C;
fn try_from_value(value: &[u8]) -> Option<Self> {
let checksum_bytes = <[u8; 4]>::try_from(value).ok()?;
Some(Self {
checksum: u32::from_be_bytes(checksum_bytes),
})
}
fn value_bytes(&self) -> Cow<'_, [u8]> {
Cow::Owned(self.checksum.to_be_bytes().to_vec())
}
}
/// The TLV of this type should be ignored when parsed. The value is zero or more
/// bytes. Can be used for data padding or alignment. Note that it can be used
/// to align only by 3 or more bytes because a TLV can not be smaller than that.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Noop {
value: Vec<u8>,
}
impl Noop {
///
///
/// # Panics
/// Panics if `value` is empty (i.e., has length of 0).
pub fn new(value: impl Into<Vec<u8>>) -> Self {
let value = value.into();
assert!(!value.is_empty(), "Noop TLV `value` cannot be empty");
Self { value }
}
}
impl Tlv for Noop {
const TYPE: u8 = PP2_TYPE_NOOP;
fn try_from_value(value: &[u8]) -> Option<Self> {
Some(Self {
value: value.to_owned(),
})
}
fn value_bytes(&self) -> Cow<'_, [u8]> {
Cow::Borrowed(&self.value)
}
}
/// The value of the type PP2_TYPE_UNIQUE_ID is an opaque byte sequence of up to
/// 128 bytes generated by the upstream proxy that uniquely identifies the
/// connection.
///
/// The unique ID can be used to easily correlate connections across multiple
/// layers of proxies, without needing to look up IP addresses and port numbers.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UniqueId {
value: Vec<u8>,
}
impl UniqueId {
///
///
/// # Panics
/// Panics if `value` is 0 bytes or larger than 128 bytes.
pub fn new(id: impl Into<Vec<u8>>) -> Self {
let value = id.into();
assert!(!value.is_empty(), "UniqueId TLV `value` cannot be empty");
assert!(
value.len() < 128,
"UniqueId TLV `value` cannot be larger than 128 bytes"
);
Self { value }
}
}
impl Tlv for UniqueId {
const TYPE: u8 = PP2_TYPE_UNIQUE_ID;
fn try_from_value(value: &[u8]) -> Option<Self> {
Some(Self {
value: value.to_owned(),
})
}
fn value_bytes(&self) -> Cow<'_, [u8]> {
Cow::Borrowed(&self.value)
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, PartialEq, Eq)]
struct SslClientFlags: u8 {
const PP2_CLIENT_SSL = 0x01;
const PP2_CLIENT_CERT_CONN = 0x02;
const PP2_CLIENT_CERT_SESS = 0x04;
}
}
/// TLS (SSL).
///
/// Heckin broken atm.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Ssl {
/// The <client> field is made of a bit field indicating which element is present.
///
/// Note, that each of these elements may lead to extra data being appended to
/// this TLV using a second level of TLV encapsulation. It is thus possible to
/// find multiple TLV values after this field. The total length of the pp2_tlv_ssl
/// TLV will reflect this.
client: SslClientFlags,
/// The <verify> field will be zero if the client presented a certificate
/// and it was successfully verified, and non-zero otherwise.
verify: bool,
/// Sub-TLVs.
tlvs: Vec<SslTlv>,
}
impl Tlv for Ssl {
const TYPE: u8 = PP2_TYPE_SSL;
fn try_from_value(value: &[u8]) -> Option<Self> {
/// The PP2_CLIENT_SSL flag indicates that the client connected over SSL/TLS. When
/// this field is present, the US-ASCII string representation of the TLS version is
/// appended at the end of the field in the TLV format using the type
/// PP2_SUBTYPE_SSL_VERSION.
const PP2_CLIENT_SSL: u8 = 0x01;
/// PP2_CLIENT_CERT_CONN indicates that the client provided a certificate over the
/// current connection.
const PP2_CLIENT_CERT_CONN: u8 = 0x02;
/// PP2_CLIENT_CERT_SESS indicates that the client provided a
/// certificate at least once over the TLS session this connection belongs to.
const PP2_CLIENT_CERT_SESS: u8 = 0x04;
// TODO: finish parsing
None
}
fn value_bytes(&self) -> Cow<'_, [u8]> {
Cow::Borrowed(&[])
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct SslTlv {}
#[cfg(test)]
mod tests {
use super::*;
// #[test]
// #[should_panic]
// fn tlv_zero_len() {
// Tlv::new(0x00, vec![]);
// }
#[test]
fn tlv_as_crc32c() {
// noop
assert_eq!(Crc32c::try_from_parts(0x04, &[0x00]), None);
assert_eq!(
Crc32c::try_from_parts(0x03, &[0x08, 0x70, 0x17, 0x7b]),
Some(Crc32c {
checksum: 141563771
})
);
}
}

View File

@@ -0,0 +1,60 @@
use std::{fmt, io, net::SocketAddr};
use arrayvec::ArrayVec;
use tokio::io::{AsyncWrite, AsyncWriteExt as _};
use crate::AddressFamily;
pub(crate) const SIGNATURE: &str = "PROXY";
#[derive(Debug, Clone)]
pub struct Header {
/// Address family.
af: AddressFamily,
/// Source address.
src: SocketAddr,
/// Destination address.
dst: SocketAddr,
}
impl Header {
pub const fn new(af: AddressFamily, src: SocketAddr, dst: SocketAddr) -> Self {
Self { af, src, dst }
}
pub const fn new_inet(src: SocketAddr, dst: SocketAddr) -> Self {
Self::new(AddressFamily::Inet, src, dst)
}
pub const fn new_inet6(src: SocketAddr, dst: SocketAddr) -> Self {
Self::new(AddressFamily::Inet6, src, dst)
}
pub fn write_to(&self, wrt: &mut impl io::Write) -> io::Result<()> {
write!(wrt, "{}", self)
}
pub async fn write_to_tokio(&self, wrt: &mut (impl AsyncWrite + Unpin)) -> io::Result<()> {
// max length of a V1 header is 107 bytes
let mut buf = ArrayVec::<_, 107>::new();
self.write_to(&mut buf)?;
wrt.write_all(&buf).await
}
}
impl fmt::Display for Header {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{proto_sig} {af} {src_ip} {dst_ip} {src_port} {dst_port}\r\n",
proto_sig = SIGNATURE,
af = self.af.v1_str(),
src_ip = self.src.ip(),
dst_ip = self.dst.ip(),
src_port = itoa::Buffer::new().format(self.src.port()),
dst_port = itoa::Buffer::new().format(self.dst.port()),
)
}
}

View File

@@ -0,0 +1,304 @@
use std::{
io,
net::{IpAddr, SocketAddr},
};
use smallvec::{smallvec, SmallVec, ToSmallVec as _};
use tokio::io::{AsyncWrite, AsyncWriteExt as _};
use crate::{
tlv::{Crc32c, Tlv},
AddressFamily, Command, TransportProtocol, Version,
};
pub(crate) const SIGNATURE: [u8; 12] = [
0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A,
];
#[derive(Debug, Clone)]
pub struct Header {
command: Command,
transport_protocol: TransportProtocol,
address_family: AddressFamily,
src: SocketAddr,
dst: SocketAddr,
tlvs: SmallVec<[(u8, SmallVec<[u8; 16]>); 4]>,
}
impl Header {
pub fn new(
command: Command,
transport_protocol: TransportProtocol,
address_family: AddressFamily,
src: impl Into<SocketAddr>,
dst: impl Into<SocketAddr>,
) -> Self {
Self {
command,
transport_protocol,
address_family,
src: src.into(),
dst: dst.into(),
tlvs: SmallVec::new(),
}
}
pub fn new_tcp_ipv4_proxy(src: impl Into<SocketAddr>, dst: impl Into<SocketAddr>) -> Self {
Self::new(
Command::Proxy,
TransportProtocol::Stream,
AddressFamily::Inet,
src,
dst,
)
}
pub fn add_tlv(&mut self, typ: u8, value: impl AsRef<[u8]>) {
self.tlvs.push((typ, SmallVec::from_slice(value.as_ref())));
}
pub fn add_typed_tlv<T: Tlv>(&mut self, tlv: T) {
self.add_tlv(T::TYPE, tlv.value_bytes());
}
fn v2_len(&self) -> u16 {
let addr_len = if self.src.is_ipv4() {
4 + 2 // 4b IPv4 + 2b port number
} else {
16 + 2 // 16b IPv6 + 2b port number
};
(addr_len * 2)
+ self
.tlvs
.iter()
.map(|(_, value)| 1 + 2 + value.len() as u16)
.sum::<u16>()
}
pub fn write_to(&self, wrt: &mut impl io::Write) -> io::Result<()> {
// PROXY v2 signature
wrt.write_all(&SIGNATURE)?;
// version | command
wrt.write_all(&[Version::V2.v2_hi() | self.command.v2_lo()])?;
// address family | transport protocol
wrt.write_all(&[self.address_family.v2_hi() | self.transport_protocol.v2_lo()])?;
// rest-of-header length
wrt.write_all(&self.v2_len().to_be_bytes())?;
tracing::debug!("proxy rest-of-header len: {}", self.v2_len());
fn write_ip_bytes_to(wrt: &mut impl io::Write, ip: IpAddr) -> io::Result<()> {
match ip {
IpAddr::V4(ip) => wrt.write_all(&ip.octets()),
IpAddr::V6(ip) => wrt.write_all(&ip.octets()),
}
}
// L3 (IP) address
write_ip_bytes_to(wrt, self.src.ip())?;
write_ip_bytes_to(wrt, self.dst.ip())?;
// L4 ports
wrt.write_all(&self.src.port().to_be_bytes())?;
wrt.write_all(&self.dst.port().to_be_bytes())?;
// TLVs
for (typ, value) in &self.tlvs {
wrt.write_all(&[*typ])?;
wrt.write_all(&(value.len() as u16).to_be_bytes())?;
wrt.write_all(value)?;
}
Ok(())
}
pub async fn write_to_tokio(&self, wrt: &mut (impl AsyncWrite + Unpin)) -> io::Result<()> {
let buf = self.to_vec();
wrt.write_all(&buf).await
}
fn to_vec(&self) -> Vec<u8> {
// TODO: figure out cap
let mut buf = Vec::with_capacity(64);
self.write_to(&mut buf).unwrap();
buf
}
pub fn has_tlv<T: Tlv>(&self) -> bool {
self.tlvs.iter().any(|&(typ, _)| typ == T::TYPE)
}
/// Calculates and adds a crc32c TLV to the PROXY header.
///
/// Uses method defined in spec.
///
/// If this is not called last thing it will be wrong.
pub fn add_crc23c_checksum(&mut self) {
// don't add a checksum if it is already set
if self.has_tlv::<Crc32c>() {
return;
}
// When the checksum is supported by the sender after constructing the header
// the sender MUST:
// - initialize the checksum field to '0's.
// - calculate the CRC32c checksum of the PROXY header as described in RFC4960,
// Appendix B [8].
// - put the resultant value into the checksum field, and leave the rest of
// the bits unchanged.
// add zeroed checksum field to TLVs
self.add_typed_tlv(Crc32c::default());
// write PROXY header to buffer
let mut buf = Vec::new();
self.write_to(&mut buf).unwrap();
// calculate CRC on buffer and update CRC TLV
let crc_calc = crc32fast::hash(&buf);
self.tlvs.last_mut().unwrap().1 = crc_calc.to_be_bytes().to_smallvec();
tracing::debug!("checksum is {}", crc_calc);
}
pub fn validate_crc32c_tlv(&self) -> Option<bool> {
// extract crc32c TLV or exit early if none is present
let crc_sent = self
.tlvs
.iter()
.filter_map(|(typ, value)| Crc32c::try_from_parts(*typ, value))
.next()?;
// If the checksum is provided as part of the PROXY header and the checksum
// functionality is supported by the receiver, the receiver MUST:
// - store the received CRC32c checksum value aside.
// - replace the 32 bits of the checksum field in the received PROXY header with
// all '0's and calculate a CRC32c checksum value of the whole PROXY header.
// - verify that the calculated CRC32c checksum is the same as the received
// CRC32c checksum. If it is not, the receiver MUST treat the TCP connection
// providing the header as invalid.
// The default procedure for handling an invalid TCP connection is to abort it.
let mut this = self.clone();
for (typ, value) in this.tlvs.iter_mut() {
if Crc32c::try_from_parts(*typ, value).is_some() {
value.fill(0);
}
}
let mut buf = Vec::new();
this.write_to(&mut buf).unwrap();
let mut crc_calc = crc32fast::hash(&buf);
Some(crc_sent.checksum == crc_calc)
}
}
#[cfg(test)]
mod tests {
use std::net::Ipv6Addr;
use const_str::hex;
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn write_v2_no_tlvs() {
let mut exp = Vec::new();
exp.extend_from_slice(&SIGNATURE); // 0-11
exp.extend_from_slice(&[0x21, 0x11]); // 12-13
exp.extend_from_slice(&[0x00, 0x0C]); // 14-15
exp.extend_from_slice(&[127, 0, 0, 1, 127, 0, 0, 2]); // 16-23
exp.extend_from_slice(&[0x04, 0xd2, 0x00, 80]); // 24-27
let header = Header::new(
Command::Proxy,
TransportProtocol::Stream,
AddressFamily::Inet,
SocketAddr::from(([127, 0, 0, 1], 1234)),
SocketAddr::from(([127, 0, 0, 2], 80)),
);
assert_eq!(header.v2_len(), 12);
assert_eq!(header.to_vec(), exp);
}
#[test]
fn write_v2_ipv6_tlv_noop() {
let mut exp = Vec::new();
exp.extend_from_slice(&SIGNATURE); // 0-11
exp.extend_from_slice(&[0x20, 0x11]); // 12-13
exp.extend_from_slice(&[0x00, 0x28]); // 14-15
exp.extend_from_slice(&hex!("00000000000000000000000000000001")); // 16-31
exp.extend_from_slice(&hex!("000102030405060708090A0B0C0D0E0F")); // 32-45
exp.extend_from_slice(&[0x00, 80, 0xff, 0xff]); // 45-49
exp.extend_from_slice(&[0x04, 0x00, 0x01, 0x00]); // 50-53 NOOP TLV
let mut header = Header::new(
Command::Local,
TransportProtocol::Stream,
AddressFamily::Inet,
SocketAddr::from((Ipv6Addr::LOCALHOST, 80)),
SocketAddr::from((
Ipv6Addr::from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]),
65535,
)),
);
header.add_tlv(0x04, [0]);
assert_eq!(header.v2_len(), 36 + 4);
assert_eq!(header.to_vec(), exp);
}
#[test]
fn write_v2_tlv_c2c() {
let mut exp = Vec::new();
exp.extend_from_slice(&SIGNATURE); // 0-11
exp.extend_from_slice(&[0x21, 0x11]); // 12-13
exp.extend_from_slice(&[0x00, 0x13]); // 14-15
exp.extend_from_slice(&[127, 0, 0, 1, 127, 0, 0, 1]); // 16-23
exp.extend_from_slice(&[0x00, 80, 0x00, 80]); // 24-27
exp.extend_from_slice(&[0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00]); // 28-35 TLV crc32c
assert_eq!(
crc32fast::hash(&exp),
// correct checksum calculated manually
u32::from_be_bytes([0x08, 0x70, 0x17, 0x7b]),
);
// re-assign actual checksum to last 4 bytes of expected byte array
exp[31..35].copy_from_slice(&[0x08, 0x70, 0x17, 0x7b]);
let mut header = Header::new(
Command::Proxy,
TransportProtocol::Stream,
AddressFamily::Inet,
SocketAddr::from(([127, 0, 0, 1], 80)),
SocketAddr::from(([127, 0, 0, 1], 80)),
);
assert!(
header.validate_crc32c_tlv().is_none(),
"header doesn't have CRC TLV added yet"
);
// add crc32c TLV to header
header.add_crc23c_checksum();
assert_eq!(header.v2_len(), 12 + 7);
assert_eq!(header.to_vec(), exp);
// struct can self-validate checksum
assert_eq!(header.validate_crc32c_tlv().unwrap(), true);
// mangle crc32c TLV and assert that validate now fails
*header.tlvs.last_mut().unwrap().1.last_mut().unwrap() = 0x00;
assert_eq!(header.validate_crc32c_tlv().unwrap(), false);
}
}

View File

@@ -1,6 +1,6 @@
# Changes
## Unreleased - 2023-xx-xx
## Unreleased
## 2.9.0
@@ -8,7 +8,7 @@
- Add `actix_rt::Runtime::tokio_runtime()` method to retrieve the underlying Tokio runtime.
- Minimum supported Rust version (MSRV) is now 1.65.
## 2.8.0 - 2022-12-21
## 2.8.0
- Add `#[track_caller]` attribute to `spawn` functions and methods. [#454]
- Update `tokio-uring` dependency to `0.4`. [#473]
@@ -17,32 +17,32 @@
[#454]: https://github.com/actix/actix-net/pull/454
[#473]: https://github.com/actix/actix-net/pull/473
## 2.7.0 - 2022-03-08
## 2.7.0
- Update `tokio-uring` dependency to `0.3`. [#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
## 2.6.0
- Update `tokio-uring` dependency to `0.2`. [#436]
[#436]: https://github.com/actix/actix-net/pull/436
## 2.5.1 - 2021-12-31
## 2.5.1
- 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
- Add `System::run_with_code` to allow retrieving the exit code on stop. [#411]
[#411]: https://github.com/actix/actix-net/pull/411
## 2.4.0 - 2021-11-05
## 2.4.0
- Add `Arbiter::try_current` for situations where thread may or may not have Arbiter context. [#408]
- Start io-uring with `System::new` when feature is enabled. [#395]
@@ -50,7 +50,7 @@
[#395]: https://github.com/actix/actix-net/pull/395
[#408]: https://github.com/actix/actix-net/pull/408
## 2.3.0 - 2021-10-11
## 2.3.0
- The `spawn` method can now resolve with non-unit outputs. [#369]
- Add experimental (semver-exempt) `io-uring` feature for enabling async file I/O on linux. [#374]
@@ -58,14 +58,14 @@
[#369]: https://github.com/actix/actix-net/pull/369
[#374]: https://github.com/actix/actix-net/pull/374
## 2.2.0 - 2021-03-29
## 2.2.0
- **BREAKING** `ActixStream::{poll_read_ready, poll_write_ready}` methods now return `Ready` object in ok variant. [#293]
- Breakage is acceptable since `ActixStream` was not intended to be public.
[#293]: https://github.com/actix/actix-net/pull/293
## 2.1.0 - 2021-02-24
## 2.1.0
- Add `ActixStream` extension trait to include readiness methods. [#276]
- Re-export `tokio::net::TcpSocket` in `net` module [#282]
@@ -73,7 +73,7 @@
[#276]: https://github.com/actix/actix-net/pull/276
[#282]: https://github.com/actix/actix-net/pull/282
## 2.0.2 - 2021-02-06
## 2.0.2
- Add `Arbiter::handle` to get a handle of an owned Arbiter. [#274]
- Add `System::try_current` for situations where actix may or may not be running a System. [#275]
@@ -81,20 +81,20 @@
[#274]: https://github.com/actix/actix-net/pull/274
[#275]: https://github.com/actix/actix-net/pull/275
## 2.0.1 - 2021-02-06
## 2.0.1
- Expose `JoinError` from Tokio. [#271]
[#271]: https://github.com/actix/actix-net/pull/271
## 2.0.0 - 2021-02-02
## 2.0.0
- Remove all Arbiter-local storage methods. [#262]
- Re-export `tokio::pin`. [#262]
[#262]: https://github.com/actix/actix-net/pull/262
## 2.0.0-beta.3 - 2021-01-31
## 2.0.0-beta.3
- Remove `run_in_tokio`, `attach_to_tokio` and `AsyncSystemRunner`. [#253]
- Return `JoinHandle` from `actix_rt::spawn`. [#253]
@@ -118,14 +118,14 @@
[#256]: https://github.com/actix/actix-net/pull/256
[#257]: https://github.com/actix/actix-net/pull/257
## 2.0.0-beta.2 - 2021-01-09
## 2.0.0-beta.2
- Add `task` mod with re-export of `tokio::task::{spawn_blocking, yield_now, JoinHandle}` [#245]
- Add default "macros" feature to allow faster compile times when using `default-features=false`.
[#245]: https://github.com/actix/actix-net/pull/245
## 2.0.0-beta.1 - 2020-12-28
## 2.0.0-beta.1
- Add `System::attach_to_tokio` method. [#173]
- Update `tokio` dependency to `1.0`. [#236]
@@ -139,13 +139,13 @@
[#207]: https://github.com/actix/actix-net/pull/207
[#236]: https://github.com/actix/actix-net/pull/236
## 1.1.1 - 2020-04-30
## 1.1.1
- Fix memory leak due to [#94] (see [#129] for more detail)
[#129]: https://github.com/actix/actix-net/issues/129
## 1.1.0 - 2020-04-08 _(YANKED)_
## 1.1.0 _(YANKED)_
- Expose `System::is_set` to check if current system has ben started [#99]
- Add `Arbiter::is_running` to check if event loop is running [#124]
@@ -155,57 +155,57 @@
[#99]: https://github.com/actix/actix-net/pull/99
[#124]: https://github.com/actix/actix-net/pull/124
## 1.0.0 - 2019-12-11
## 1.0.0
- Update dependencies
## 1.0.0-alpha.3 - 2019-12-07
## 1.0.0-alpha.3
- Migrate to tokio 0.2
- Fix compilation on non-unix platforms
## 1.0.0-alpha.2 - 2019-12-02
## 1.0.0-alpha.2
- Export `main` and `test` attribute macros
- Export `time` module (re-export of tokio-timer)
- Export `net` module (re-export of tokio-net)
## 1.0.0-alpha.1 - 2019-11-22
## 1.0.0-alpha.1
- Migrate to std::future and tokio 0.2
## 0.2.6 - 2019-11-14
## 0.2.6
- Allow to join arbiter's thread. #60
- Fix arbiter's thread panic message.
## 0.2.5 - 2019-09-02
## 0.2.5
- Add arbiter specific storage
## 0.2.4 - 2019-07-17
## 0.2.4
- Avoid a copy of the Future when initializing the Box. #29
## 0.2.3 - 2019-06-22
## 0.2.3
- Allow to start System using existing CurrentThread Handle #22
## 0.2.2 - 2019-03-28
## 0.2.2
- Moved `blocking` module to `actix-threadpool` crate
## 0.2.1 - 2019-03-11
## 0.2.1
- Added `blocking` module
- Added `Arbiter::exec_fn` - execute fn on the arbiter's thread
- Added `Arbiter::exec` - execute fn on the arbiter's thread and wait result
## 0.2.0 - 2019-03-06
## 0.2.0
- `run` method returns `io::Result<()>`
- Removed `Handle`
## 0.1.0 - 2018-12-09
## 0.1.0
- Initial release

View File

@@ -1,28 +1,28 @@
# Changes
## Unreleased - 2023-xx-xx
## Unreleased
- Minimum supported Rust version (MSRV) is now 1.65.
## 2.0.2 - 2021-12-18
## 2.0.2
- Service types can now be `Send` and `'static` regardless of request, response, and config types, etc. [#397]
[#397]: https://github.com/actix/actix-net/pull/397
## 2.0.1 - 2021-10-11
## 2.0.1
- Documentation fix. [#388]
[#388]: https://github.com/actix/actix-net/pull/388
## 2.0.0 - 2021-04-16
## 2.0.0
- Removed pipeline and related structs/functions. [#335]
[#335]: https://github.com/actix/actix-net/pull/335
## 2.0.0-beta.5 - 2021-03-15
## 2.0.0-beta.5
- Add default `Service` trait impl for `Rc<S: Service>` and `&S: Service`. [#288]
- Add `boxed::rc_service` function for constructing `boxed::RcService` type [#290]
@@ -30,7 +30,7 @@
[#288]: https://github.com/actix/actix-net/pull/288
[#290]: https://github.com/actix/actix-net/pull/290
## 2.0.0-beta.4 - 2021-02-04
## 2.0.0-beta.4
- `Service::poll_ready` and `Service::call` receive `&self`. [#247]
- `apply_fn` and `apply_fn_factory` now receive `Fn(Req, &Service)` function type. [#247]
@@ -39,17 +39,17 @@
[#247]: https://github.com/actix/actix-net/pull/247
## 2.0.0-beta.3 - 2021-01-09
## 2.0.0-beta.3
- The `forward_ready!` macro converts errors. [#246]
[#246]: https://github.com/actix/actix-net/pull/246
## 2.0.0-beta.2 - 2021-01-03
## 2.0.0-beta.2
- Remove redundant type parameter from `map_config`.
## 2.0.0-beta.1 - 2020-12-28
## 2.0.0-beta.1
- `Service`, other traits, and many type signatures now take the the request type as a type parameter instead of an associated type. [#232]
- Add `always_ready!` and `forward_ready!` macros. [#233]
@@ -62,82 +62,82 @@
[#233]: https://github.com/actix/actix-net/pull/233
[#235]: https://github.com/actix/actix-net/pull/235
## 1.0.6 - 2020-08-09
## 1.0.6
- Removed unsound custom Cell implementation that allowed obtaining several mutable references to the same data, which is undefined behavior in Rust and could lead to violations of memory safety. External code could obtain several mutable references to the same data through service combinators. Attempts to acquire several mutable references to the same data will instead result in a panic.
## 1.0.5 - 2020-01-16
## 1.0.5
- Fixed unsoundness in .and_then()/.then() service combinators.
## 1.0.4 - 2020-01-15
## 1.0.4
- Revert 1.0.3 change
## 1.0.3 - 2020-01-15
## 1.0.3
- Fixed unsoundness in `AndThenService` impl.
## 1.0.2 - 2020-01-08
## 1.0.2
- Add `into_service` helper function.
## 1.0.1 - 2019-12-22
## 1.0.1
- `map_config()` and `unit_config()` now accept `IntoServiceFactory` type.
## 1.0.0 - 2019-12-11
## 1.0.0
- Add Clone impl for Apply service
## 1.0.0-alpha.4 - 2019-12-08
## 1.0.0-alpha.4
- Renamed `service_fn` to `fn_service`
- Renamed `factory_fn` to `fn_factory`
- Renamed `factory_fn_cfg` to `fn_factory_with_config`
## 1.0.0-alpha.3 - 2019-12-06
## 1.0.0-alpha.3
- Add missing Clone impls
- Restore `Transform::map_init_err()` combinator
- Restore `Service/Factory::apply_fn()` in form of `Pipeline/Factory::and_then_apply_fn()`
- Optimize service combinators and futures memory layout
## 1.0.0-alpha.2 - 2019-12-02
## 1.0.0-alpha.2
- Use owned config value for service factory
- Renamed BoxedNewService/BoxedService to BoxServiceFactory/BoxService
## 1.0.0-alpha.1 - 2019-11-25
## 1.0.0-alpha.1
- Migrated to `std::future`
- `NewService` renamed to `ServiceFactory`
- Added `pipeline` and `pipeline_factory` function
## 0.4.2 - 2019-08-27
## 0.4.2
- Check service readiness for `new_apply_cfg` combinator
## 0.4.1 - 2019-06-06
## 0.4.1
- Add `new_apply_cfg` function
## 0.4.0 - 2019-05-12
## 0.4.0
- Add `NewService::map_config` and `NewService::unit_config` combinators.
- Use associated type for `NewService` config.
- Change `apply_cfg` function.
- Renamed helper functions.
## 0.3.6 - 2019-04-07
## 0.3.6
- Poll boxed service call result immediately
## 0.3.5 - 2019-03-29
## 0.3.5
- Add `impl<S: Service> Service for Rc<RefCell<S>>`.
## 0.3.4 - 2019-03-12
## 0.3.4
- Add `Transform::from_err()` combinator
- Add `apply_fn` helper
@@ -145,37 +145,37 @@
- Add `apply_transform` helper
- Add `apply_cfg` helper
## 0.3.3 - 2019-03-09
## 0.3.3
- Add `ApplyTransform` new service for transform and new service.
- Add `NewService::apply_cfg()` combinator, allows to use nested `NewService` with different config parameter.
- Revert IntoFuture change
## 0.3.2 - 2019-03-04
## 0.3.2
- Change `NewService::Future` and `Transform::Future` to the `IntoFuture` trait.
- Export `AndThenTransform` type
## 0.3.1 - 2019-03-04
## 0.3.1
- Simplify Transform trait
## 0.3.0 - 2019-03-02
## 0.3.0
- Added boxed NewService and Service.
- Added `Config` parameter to `NewService` trait.
- Added `Config` parameter to `NewTransform` trait.
## 0.2.2 - 2019-02-19
## 0.2.2
- Added `NewService` impl for `Rc<S> where S: NewService`
- Added `NewService` impl for `Arc<S> where S: NewService`
## 0.2.1 - 2019-02-03
## 0.2.1
- Generalize `.apply` combinator with Transform trait
## 0.2.0 - 2019-02-01
## 0.2.0
- Use associated type instead of generic for Service definition.
- Before:
@@ -194,31 +194,31 @@
}
```
## 0.1.6 - 2019-01-24
## 0.1.6
- Use `FnMut` instead of `Fn` for .apply() and .map() combinators and `FnService` type
- Change `.apply()` error semantic, new service's error is `From<Self::Error>`
## 0.1.5 - 2019-01-13
## 0.1.5
- Make `Out::Error` convertible from `T::Error` for apply combinator
## 0.1.4 - 2019-01-11
## 0.1.4
- Use `FnMut` instead of `Fn` for `FnService`
## 0.1.3 - 2018-12-12
## 0.1.3
- Split service combinators to separate trait
## 0.1.2 - 2018-12-12
## 0.1.2
- Release future early for `.and_then()` and `.then()` combinators
## 0.1.1 - 2018-12-09
## 0.1.1
- Added Service impl for `Box<S: Service>`
## 0.1.0 - 2018-12-09
## 0.1.0
- Initial import

View File

@@ -2,6 +2,10 @@
## Unreleased
## 3.1.1
- Fix `rustls` v0.21 version requirement.
## 3.1.0
- Support Rustls v0.21.

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-tls"
version = "3.1.0"
version = "3.1.1"
authors = [
"Nikolay Kim <fafhrd91@gmail.com>",
"Rob Ede <robjtede@icloud.com>",
@@ -17,6 +17,12 @@ rust-version.workspace = true
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.cargo-machete]
ignored = [
"rustls_021", # specified to force version with add_trust_anchors method
"rustls_webpki_0101", # specified to force secure version
]
[features]
default = ["accept", "connect"]
@@ -60,7 +66,7 @@ tracing = { version = "0.1.30", default-features = false, features = ["log"] }
http = { version = "0.2.3", optional = true }
# openssl
tls-openssl = { package = "openssl", version = "0.10.48", optional = true }
tls-openssl = { package = "openssl", version = "0.10.55", optional = true }
tokio-openssl = { version = "0.6", optional = true }
# rustls v0.20
@@ -68,6 +74,8 @@ tokio-rustls-023 = { package = "tokio-rustls", version = "0.23", optional = true
webpki-roots-022 = { package = "webpki-roots", version = "0.22", optional = true }
# rustls v0.21
rustls-021 = { package = "rustls", version = "0.21.6" }
rustls-webpki-0101 = { package = "rustls-webpki", version = "0.101.4" }
tokio-rustls-024 = { package = "tokio-rustls", version = "0.24", optional = true }
webpki-roots-025 = { package = "webpki-roots", version = "0.25", optional = true }
@@ -81,7 +89,6 @@ actix-server = "2"
bytes = "1"
env_logger = "0.10"
futures-util = { version = "0.3.17", default-features = false, features = ["sink"] }
log = "0.4"
rcgen = "0.11"
rustls-pemfile = "1"
tokio-rustls-024 = { package = "tokio-rustls", version = "0.24", features = ["dangerous_configuration"] }

View File

@@ -1,9 +1,9 @@
# Changes
## Unreleased - 2023-xx-xx
## Unreleased
- Minimum supported Rust version (MSRV) is now 1.65.
## 0.1.0 - 2020-01-15
## 0.1.0
- Initial release

View File

@@ -1,24 +1,24 @@
# Changes
## Unreleased - 2023-xx-xx
## Unreleased
- Minimum supported Rust version (MSRV) is now 1.65.
## 3.0.1 - 2022-10-21
## 3.0.1
- Minimum supported Rust version (MSRV) is now 1.57.
## 3.0.0 - 2021-04-16
## 3.0.0
- No significant changes from `3.0.0-beta.4`.
## 3.0.0-beta.4 - 2021-04-01
## 3.0.0-beta.4
- Add `future::Either` type. [#305]
[#305]: https://github.com/actix/actix-net/pull/305
## 3.0.0-beta.3 - 2021-04-01
## 3.0.0-beta.3
- Moved `mpsc` to own crate `local-channel`. [#301]
- Moved `task::LocalWaker` to own crate `local-waker`. [#301]
@@ -28,13 +28,13 @@
[#301]: https://github.com/actix/actix-net/pull/301
## 3.0.0-beta.2 - 2021-02-06
## 3.0.0-beta.2
- Update `actix-rt` to `2.0.0`. [#273]
[#273]: https://github.com/actix/actix-net/pull/273
## 3.0.0-beta.1 - 2020-12-28
## 3.0.0-beta.1
- Update `bytes` dependency to `1`. [#237]
- Use `pin-project-lite` to replace `pin-project`. [#229]
@@ -43,139 +43,139 @@
[#229]: https://github.com/actix/actix-net/pull/229
[#237]: https://github.com/actix/actix-net/pull/237
## 2.0.0 - 2020-08-23
## 2.0.0
- No changes from beta 1.
## 2.0.0-beta.1 - 2020-08-19
## 2.0.0-beta.1
- Upgrade `tokio-util` to `0.3`.
- Remove unsound custom Cell and use `std::cell::RefCell` instead, as well as `actix-service`.
- Rename method to correctly spelled `LocalWaker::is_registered`.
## 1.0.6 - 2020-01-08
## 1.0.6
- Add `Clone` impl for `condition::Waiter`.
## 1.0.5 - 2020-01-08
## 1.0.5
- Add `Condition` type.
- Add `Pool` of one-shot's.
## 1.0.4 - 2019-12-20
## 1.0.4
- Add methods to check `LocalWaker` registration state.
## 1.0.3 - 2019-12-11
## 1.0.3
- Revert InOrder service changes
## 1.0.2 - 2019-12-11
## 1.0.2
- Allow to create `framed::Dispatcher` with custom `mpsc::Receiver`.
- Add `oneshot::Sender::is_canceled()` method.
## 1.0.1 - 2019-12-11
## 1.0.1
- Optimize InOrder service.
## 1.0.0 - 2019-12-11
## 1.0.0
- Simplify oneshot and mpsc implementations.
## 1.0.0-alpha.3 - 2019-12-07
## 1.0.0-alpha.3
- Migrate to tokio 0.2.
- Fix oneshot.
## 1.0.0-alpha.2 - 2019-12-02
## 1.0.0-alpha.2
- Migrate to `std::future`.
## 0.4.7 - 2019-10-14
## 0.4.7
- Re-register task on every framed transport poll.
## 0.4.6 - 2019-10-08
## 0.4.6
- Refactor `Counter` type. register current task in available method.
## 0.4.5 - 2019-07-19
## 0.4.5
- Deprecated `CloneableService` as it is not safe.
## 0.4.4 - 2019-07-17
## 0.4.4
- Undeprecate `FramedTransport` as it is actually useful.
## 0.4.3 - 2019-07-17
## 0.4.3
- Deprecate `CloneableService` as it is not safe and in general not very useful.
- Deprecate `FramedTransport` in favor of `actix-ioframe`.
## 0.4.2 - 2019-06-26
## 0.4.2
- Do not block on sink drop for FramedTransport.
## 0.4.1 - 2019-05-15
## 0.4.1
- Change `Either` constructor.
## 0.4.0 - 2019-05-11
## 0.4.0
- Change `Either` to handle two nexted services.
- Upgrade actix-service 0.4.
- Removed framed related services.
- Removed stream related services.
## 0.3.5 - 2019-04-04
## 0.3.5
- Allow to send messages to `FramedTransport` via mpsc channel.
- Remove `'static` constraint from Clonable service.
## 0.3.4 - 2019-03-12
## 0.3.4
- `TimeoutService`, `InOrderService`, `InFlightService` accepts generic IntoService services.
- Fix `InFlightService::poll_ready()` nested service readiness check.
- Fix `InOrderService::poll_ready()` nested service readiness check.
## 0.3.3 - 2019-03-09
## 0.3.3
- Revert IntoFuture change.
- Add generic config param for IntoFramed and TakeOne new services.
## 0.3.2 - 2019-03-04
## 0.3.2
- Use IntoFuture for new services.
## 0.3.1 - 2019-03-04
## 0.3.1
- Use new type of transform trait.
## 0.3.0 - 2019-03-02
## 0.3.0
- Use new `NewService` trait
- BoxedNewService`and`BoxedService` types moved to actix-service crate.
## 0.2.4 - 2019-02-21
## 0.2.4
- Custom `BoxedNewService` implementation.
## 0.2.3 - 2019-02-21
## 0.2.3
- Add `BoxedNewService` and `BoxedService`.
## 0.2.2 - 2019-02-11
## 0.2.2
- Add `Display` impl for `TimeoutError`.
- Add `Display` impl for `InOrderError`.
## 0.2.1 - 2019-02-06
## 0.2.1
- Add `InOrder` service. the service yields responses as they become available, in the order that their originating requests were submitted to the service.
- Convert `Timeout` and `InFlight` services to a transforms.
## 0.2.0 - 2019-02-01
## 0.2.0
- Fix framed transport error handling.
- Added Clone impl for Either service.
@@ -183,6 +183,6 @@
- Added Service and NewService for Stream dispatcher.
- Switch to actix-service 0.2.
## 0.1.0 - 2018-12-09
## 0.1.0
- Move utils services to separate crate.

View File

@@ -1,25 +1,25 @@
# Changes
## Unreleased - 2023-xx-xx
## Unreleased
## 1.3.0 - 2023-03-03
## 1.3.0
- Implement `AsRef<ByteString>` for `ByteString`.
## 1.2.1 - 2022-11-12
## 1.2.1
- Fix `#[no_std]` compatibility. [#471]
[#471]: https://github.com/actix/actix-net/pull/471
## 1.2.0 - 2022-11-07
## 1.2.0
- Add `ByteString::slice_ref` which can safely slice a `ByteString` into a new one with zero copy. [#470]
- Minimum supported Rust version (MSRV) is now 1.57.
[#470]: https://github.com/actix/actix-net/pull/470
## 1.1.0 - 2022-06-11
## 1.1.0
- Implement `From<Box<str>>` for `ByteString`. [#458]
- Implement `Into<String>` for `ByteString`. [#458]
@@ -27,7 +27,7 @@
[#458]: https://github.com/actix/actix-net/pull/458
## 1.0.0 - 2020-12-31
## 1.0.0
- Update `bytes` dependency to `1`.
- Add array and slice of `u8` impls of `TryFrom` up to 32 in length.
@@ -35,27 +35,27 @@
- `ByteString::new` is now a `const fn`.
- Crate is now `#[no_std]` compatible.
## 0.1.5 - 2020-03-30
## 0.1.5
- Serde support
## 0.1.4 - 2020-01-14
## 0.1.4
- Fix `AsRef<str>` impl
## 0.1.3 - 2020-01-13
## 0.1.3
- Add `PartialEq<T: AsRef<str>>`, `AsRef<[u8]>` impls
## 0.1.2 - 2019-12-22
## 0.1.2
- Fix `new()` method
- Make `ByteString::from_static()` and `ByteString::from_bytes_unchecked()` methods const.
## 0.1.1 - 2019-12-07
## 0.1.1
- Fix hash impl
## 0.1.0 - 2019-12-07
## 0.1.0
- Initial release

View File

@@ -22,4 +22,3 @@ serde = { version = "1.0", optional = true }
ahash = { version = "0.8", default-features = false }
serde_json = "1.0"
static_assertions = "1.1"
rustversion = "1"

View File

@@ -1,17 +1,19 @@
# Changes
## Unreleased - 2023-xx-xx
## Unreleased
## 0.1.4
- Minimum supported Rust version (MSRV) is now 1.65.
## 0.1.3 - 2022-05-03
## 0.1.3
- Minimum supported Rust version (MSRV) is now 1.49.
## 0.1.2 - 2021-04-01
## 0.1.2
- No significant changes from `0.1.1`.
## 0.1.1 - 2021-03-29
## 0.1.1
- Move local mpsc channel to it's own crate.
- Move local MPSC channel to it's own crate.

View File

@@ -1,22 +1,22 @@
[package]
name = "local-channel"
version = "0.1.3"
version = "0.1.4"
description = "A non-threadsafe multi-producer, single-consumer, futures-aware, FIFO queue"
authors = [
"Nikolay Kim <fafhrd91@gmail.com>",
"Rob Ede <robjtede@icloud.com>",
]
repository = "https://github.com/actix/actix-net.git"
repository = "https://github.com/actix/actix-net"
keywords = ["channel", "local", "futures"]
license = "MIT OR Apache-2.0"
license.workspace = true
edition.workspace = true
rust-version.workspace = true
[dependencies]
futures-core = "0.3.17"
futures-sink = "0.3.17"
futures-util = { version = "0.3.17", default-features = false }
local-waker = "0.1"
[dev-dependencies]
futures-util = { version = "0.3.17", default-features = false }
tokio = { version = "1.23.1", features = ["rt", "macros"] }

View File

@@ -4,6 +4,7 @@ use alloc::{collections::VecDeque, rc::Rc};
use core::{
cell::RefCell,
fmt,
future::poll_fn,
pin::Pin,
task::{Context, Poll},
};
@@ -11,7 +12,6 @@ use std::error::Error;
use futures_core::stream::Stream;
use futures_sink::Sink;
use futures_util::future::poll_fn;
use local_waker::LocalWaker;
/// Creates a unbounded in-memory channel with buffered storage.

View File

@@ -1,17 +1,17 @@
# Changes
## Unreleased - 2023-xx-xx
## Unreleased
- Minimum supported Rust version (MSRV) is now 1.65.
## 0.1.3 - 2022-05-03
## 0.1.3
- Minimum supported Rust version (MSRV) is now 1.49.
## 0.1.2 - 2021-12-18
## 0.1.2
- Fix crate metadata.
## 0.1.1 - 2021-03-29
## 0.1.1
- Move `LocalWaker` to it's own crate.