Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into HEAD
Browse files Browse the repository at this point in the history
  • Loading branch information
jordy25519 committed Nov 5, 2024
2 parents 66841b7 + 7d338cb commit adcfc66
Show file tree
Hide file tree
Showing 26 changed files with 132 additions and 69 deletions.
20 changes: 15 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,22 @@ jobs:
name: Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
with:
components: rustfmt
- run: cargo fmt --all --check

clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- run: cargo clippy --all --tests --all-features -- -D warnings

test:
name: Test
runs-on: ubuntu-latest
Expand All @@ -24,7 +34,7 @@ jobs:

steps:
- name: Checkout sources
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install toolchain
uses: dtolnay/rust-toolchain@master
Expand All @@ -50,11 +60,11 @@ jobs:
strategy:
matrix:
rust:
- 1.60.0
- 1.63.0

steps:
- name: Checkout sources
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install toolchain
uses: dtolnay/rust-toolchain@master
Expand All @@ -80,7 +90,7 @@ jobs:

steps:
- name: Checkout sources
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install toolchain
uses: dtolnay/rust-toolchain@master
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
# 0.24.0

- Raised MSRV to 1.63 to match `tokio-tungstenite`.
- Connecting to WSS URL without TLS features specified results in a better error.
- Handshake will now flush after completion to be safe (works better with buffered streams).

# 0.23.0

- Disable default features for `rustls` giving the user more flexibility.

# 0.22.0
- Make `url` optional.
- Add a builder for convenient headers and subprotocols construction.
- Update `rustls` dependency.

# 0.21.0
- Fix read-predominant auto pong responses not flushing when hitting WouldBlock errors.
Expand Down
12 changes: 7 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ authors = ["Alexey Galakhov", "Daniel Abramov"]
license = "MIT OR Apache-2.0"
readme = "README.md"
homepage = "https://github.com/snapview/tungstenite-rs"
documentation = "https://docs.rs/tungstenite/0.22.0"
documentation = "https://docs.rs/tungstenite/0.24.0"
repository = "https://github.com/snapview/tungstenite-rs"
version = "0.22.0"
edition = "2018"
rust-version = "1.60"
version = "0.24.0"
edition = "2021"
rust-version = "1.63"
include = ["benches/**/*", "src/**/*", "examples/**/*", "LICENSE-*", "README.md", "CHANGELOG.md"]

[package.metadata.docs.rs]
Expand Down Expand Up @@ -53,6 +53,8 @@ version = "0.2.3"

[dependencies.rustls]
optional = true
default-features = false
features = ["std"]
version = "0.23.0"

[dependencies.rustls-pki-types]
Expand All @@ -61,7 +63,7 @@ version = "1.0"

[dependencies.rustls-native-certs]
optional = true
version = "0.7.0"
version = "0.8.0"

[dependencies.webpki-roots]
optional = true
Expand Down
6 changes: 3 additions & 3 deletions benches/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl<const CHUNK_SIZE: usize> Buf for StackReadBuffer<CHUNK_SIZE> {
}

fn advance(&mut self, cnt: usize) {
Buf::advance(self.as_cursor_mut(), cnt)
Buf::advance(self.as_cursor_mut(), cnt);
}
}

Expand Down Expand Up @@ -114,10 +114,10 @@ fn benchmark(c: &mut Criterion) {
group.throughput(Throughput::Bytes(STREAM_SIZE as u64));
group.bench_function("InputBuffer", |b| b.iter(|| input_buffer(black_box(stream.clone()))));
group.bench_function("ReadBuffer (stack)", |b| {
b.iter(|| stack_read_buffer(black_box(stream.clone())))
b.iter(|| stack_read_buffer(black_box(stream.clone())));
});
group.bench_function("ReadBuffer (heap)", |b| {
b.iter(|| heap_read_buffer(black_box(stream.clone())))
b.iter(|| heap_read_buffer(black_box(stream.clone())));
});
group.finish();
}
Expand Down
2 changes: 1 addition & 1 deletion benches/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ fn benchmark(c: &mut Criterion) {
ws.flush().unwrap();
},
BatchSize::SmallInput,
)
);
});
}

Expand Down
4 changes: 2 additions & 2 deletions examples/autobahn-client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ fn get_case_count() -> Result<u32> {
}

fn update_reports() -> Result<()> {
let (mut socket, _) = connect(&format!("ws://localhost:9001/updateReports?agent={}", AGENT))?;
let (mut socket, _) = connect(format!("ws://localhost:9001/updateReports?agent={AGENT}"))?;
socket.close(None)?;
Ok(())
}

fn run_test(case: u32) -> Result<()> {
info!("Running test case {}", case);
let case_url = &format!("ws://localhost:9001/runCase?case={}&agent={}", case, AGENT);
let case_url = format!("ws://localhost:9001/runCase?case={case}&agent={AGENT}");

let mut config = WebSocketConfig::default();
config.compression = Some(DeflateConfig::default());
Expand Down
6 changes: 3 additions & 3 deletions examples/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ fn main() {
println!("Connected to the server");
println!("Response HTTP code: {}", response.status());
println!("Response contains the following headers:");
for (ref header, _value) in response.headers() {
println!("* {}", header);
for (header, _value) in response.headers() {
println!("* {header}");
}

socket.send(Message::Text("Hello WebSocket".into())).unwrap();
loop {
let msg = socket.read().expect("Error reading message");
println!("Received: {}", msg);
println!("Received: {msg}");
}
// socket.close(None);
}
4 changes: 2 additions & 2 deletions examples/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ fn main() {
println!("Received a new ws handshake");
println!("The request's path is: {}", req.uri().path());
println!("The request's headers are:");
for (ref header, _value) in req.headers() {
println!("* {}", header);
for (header, _value) in req.headers() {
println!("* {header}");
}

// Let's add an additional header to our response to the client.
Expand Down
6 changes: 3 additions & 3 deletions examples/srv_accept_unmasked_frames.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ fn main() {
println!("Received a new ws handshake");
println!("The request's path is: {}", req.uri().path());
println!("The request's headers are:");
for (ref header, _value) in req.headers() {
println!("* {}", header);
for (header, _value) in req.headers() {
println!("* {header}");
}

// Let's add an additional header to our response to the client.
Expand All @@ -39,7 +39,7 @@ fn main() {
loop {
let msg = websocket.read().unwrap();
if msg.is_binary() || msg.is_text() {
println!("received message {}", msg);
println!("received message {msg}");
}
}
});
Expand Down
2 changes: 1 addition & 1 deletion src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl<const CHUNK_SIZE: usize> Buf for ReadBuffer<CHUNK_SIZE> {
}

fn advance(&mut self, cnt: usize) {
Buf::advance(self.as_cursor_mut(), cnt)
Buf::advance(self.as_cursor_mut(), cnt);
}
}

Expand Down
15 changes: 11 additions & 4 deletions src/client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! Methods to connect to a WebSocket as a client.

use std::{
convert::TryFrom,
io::{Read, Write},
net::{SocketAddr, TcpStream, ToSocketAddrs},
result::Result as StdResult,
Expand Down Expand Up @@ -52,6 +51,12 @@ pub fn connect_with_config<Req: IntoClientRequest>(
) -> Result<(WebSocket<MaybeTlsStream<TcpStream>>, Response)> {
let uri = request.uri();
let mode = uri_mode(uri)?;

#[cfg(not(any(feature = "native-tls", feature = "__rustls-tls")))]
if let Mode::Tls = mode {
return Err(Error::Url(UrlError::TlsFeatureNotEnabled));
}

let host = request.uri().host().ok_or(Error::Url(UrlError::NoHostName))?;
let host = if host.starts_with('[') { &host[1..host.len() - 1] } else { host };
let port = uri.port_u16().unwrap_or(match mode {
Expand Down Expand Up @@ -83,14 +88,14 @@ pub fn connect_with_config<Req: IntoClientRequest>(
let (parts, _) = request.into_client_request()?.into_parts();
let mut uri = parts.uri.clone();

for attempt in 0..(max_redirects + 1) {
for attempt in 0..=max_redirects {
let request = create_request(&parts, &uri);

match try_client_handshake(request, config) {
Err(Error::Http(res)) if res.status().is_redirection() && attempt < max_redirects => {
if let Some(location) = res.headers().get("Location") {
uri = location.to_str()?.parse::<Uri>()?;
debug!("Redirecting to {:?}", uri);
debug!("Redirecting to {uri:?}");
continue;
} else {
warn!("No `Location` found in redirect");
Expand Down Expand Up @@ -124,7 +129,7 @@ pub fn connect<Req: IntoClientRequest>(

fn connect_to_some(addrs: &[SocketAddr], uri: &Uri) -> Result<TcpStream> {
for addr in addrs {
debug!("Trying to contact {} at {}...", uri, addr);
debug!("Trying to contact {uri} at {addr}...");
if let Ok(stream) = TcpStream::connect(addr) {
return Ok(stream);
}
Expand All @@ -150,6 +155,7 @@ pub fn uri_mode(uri: &Uri) -> Result<Mode> {
/// Use this function if you need a nonblocking handshake support or if you
/// want to use a custom stream like `mio::net::TcpStream` or `openssl::ssl::SslStream`.
/// Any stream supporting `Read + Write` will do.
#[allow(clippy::result_large_err)]
pub fn client_with_config<Stream, Req>(
request: Req,
stream: Stream,
Expand All @@ -167,6 +173,7 @@ where
/// Use this function if you need a nonblocking handshake support or if you
/// want to use a custom stream like `mio::net::TcpStream` or `openssl::ssl::SslStream`.
/// Any stream supporting `Read + Write` will do.
#[allow(clippy::result_large_err)]
pub fn client<Stream, Req>(
request: Req,
stream: Stream,
Expand Down
10 changes: 4 additions & 6 deletions src/handshake/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ pub fn generate_request(

fn extract_subprotocols_from_request(request: &Request) -> Result<Option<Vec<String>>> {
if let Some(subprotocols) = request.headers().get("Sec-WebSocket-Protocol") {
Ok(Some(subprotocols.to_str()?.split(",").map(|s| s.to_string()).collect()))
Ok(Some(subprotocols.to_str()?.split(',').map(ToString::to_string).collect()))
} else {
Ok(None)
}
Expand Down Expand Up @@ -394,9 +394,9 @@ mod tests {
#[test]
fn random_keys() {
let k1 = generate_key();
println!("Generated random key 1: {}", k1);
println!("Generated random key 1: {k1}");
let k2 = generate_key();
println!("Generated random key 2: {}", k2);
println!("Generated random key 2: {k2}");
assert_ne!(k1, k2);
assert_eq!(k1.len(), k2.len());
assert_eq!(k1.len(), 24);
Expand All @@ -416,9 +416,7 @@ mod tests {
Upgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: {key}\r\n\
\r\n",
host = host,
key = key
\r\n"
)
.into_bytes()
}
Expand Down
14 changes: 13 additions & 1 deletion src/handshake/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ impl<Stream: Read + Write> HandshakeMachine<Stream> {
..self
})
} else {
RoundResult::StageFinished(StageResult::DoneWriting(self.stream))
RoundResult::Incomplete(HandshakeMachine {
state: HandshakeState::Flushing,
..self
})
})
} else {
Ok(RoundResult::WouldBlock(HandshakeMachine {
Expand All @@ -90,6 +93,13 @@ impl<Stream: Read + Write> HandshakeMachine<Stream> {
}))
}
}
HandshakeState::Flushing => Ok(match self.stream.flush().no_block()? {
Some(()) => RoundResult::StageFinished(StageResult::DoneWriting(self.stream)),
None => RoundResult::WouldBlock(HandshakeMachine {
state: HandshakeState::Flushing,
..self
}),
}),
}
}
}
Expand Down Expand Up @@ -128,6 +138,8 @@ enum HandshakeState {
Reading(ReadBuffer, AttackCheck),
/// Sending data to the peer.
Writing(Cursor<Vec<u8>>),
/// Flushing data to ensure that all intermediately buffered contents reach their destination.
Flushing,
}

/// Attack mitigation. Contains counters needed to prevent DoS attacks
Expand Down
4 changes: 2 additions & 2 deletions src/handshake/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl<Role: HandshakeRole> fmt::Debug for HandshakeError<Role> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
HandshakeError::Interrupted(_) => write!(f, "HandshakeError::Interrupted(...)"),
HandshakeError::Failure(ref e) => write!(f, "HandshakeError::Failure({:?})", e),
HandshakeError::Failure(ref e) => write!(f, "HandshakeError::Failure({e:?})"),
}
}
}
Expand All @@ -73,7 +73,7 @@ impl<Role: HandshakeRole> fmt::Display for HandshakeError<Role> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
HandshakeError::Interrupted(_) => write!(f, "Interrupted handshake (WouldBlock)"),
HandshakeError::Failure(ref e) => write!(f, "{}", e),
HandshakeError::Failure(ref e) => write!(f, "{e}"),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/handshake/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ fn create_parts<T>(request: &HttpRequest<T>) -> Result<Builder> {
.headers()
.get("Connection")
.and_then(|h| h.to_str().ok())
.map(|h| h.split(|c| c == ' ' || c == ',').any(|p| p.eq_ignore_ascii_case("Upgrade")))
.map(|h| h.split([' ', ',']).any(|p| p.eq_ignore_ascii_case("Upgrade")))
.unwrap_or(false)
{
return Err(Error::Protocol(ProtocolError::MissingConnectionUpgradeHeader));
Expand Down
6 changes: 3 additions & 3 deletions src/protocol/frame/coding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl fmt::Display for Data {
Data::Continue => write!(f, "CONTINUE"),
Data::Text => write!(f, "TEXT"),
Data::Binary => write!(f, "BINARY"),
Data::Reserved(x) => write!(f, "RESERVED_DATA_{}", x),
Data::Reserved(x) => write!(f, "RESERVED_DATA_{x}"),
}
}
}
Expand All @@ -57,7 +57,7 @@ impl fmt::Display for Control {
Control::Close => write!(f, "CLOSE"),
Control::Ping => write!(f, "PING"),
Control::Pong => write!(f, "PONG"),
Control::Reserved(x) => write!(f, "RESERVED_CONTROL_{}", x),
Control::Reserved(x) => write!(f, "RESERVED_CONTROL_{x}"),
}
}
}
Expand Down Expand Up @@ -197,7 +197,7 @@ impl CloseCode {
impl fmt::Display for CloseCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let code: u16 = self.into();
write!(f, "{}", code)
write!(f, "{code}")
}
}

Expand Down
Loading

0 comments on commit adcfc66

Please sign in to comment.