Skip to content

Commit

Permalink
fix: Passive mode with custom provided TcpStream (#91)
Browse files Browse the repository at this point in the history
* fix: Passive mode with custom provided TcpStream

* fix: ci

* fix: ci
  • Loading branch information
veeso authored Oct 14, 2024
1 parent 6ff024d commit d328e6c
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 69 deletions.
41 changes: 9 additions & 32 deletions .github/workflows/cargo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,50 +10,27 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
override: true
components: rustfmt, clippy
- name: Setup containers
run: docker-compose -f "tests/docker-compose.yml" up -d --build
run: docker compose -f "tests/docker-compose.yml" up -d --build
- name: Build simple
uses: actions-rs/cargo@v1
with:
command: build
args: --package suppaftp
run: cargo build --package suppaftp
- name: Build secure (native-tls)
uses: actions-rs/cargo@v1
with:
command: build
args: --features native-tls,deprecated --package suppaftp
run: cargo build --features native-tls,deprecated --package suppaftp
- name: Build secure (rustls)
uses: actions-rs/cargo@v1
with:
command: build
args: --features rustls,deprecated --package suppaftp
run: cargo build --features rustls,deprecated --package suppaftp
- name: Build async
uses: actions-rs/cargo@v1
with:
command: build
args: --features async,deprecated --package suppaftp
run: cargo build --features async,deprecated --package suppaftp
- name: Build async-native-tls
uses: actions-rs/cargo@v1
with:
command: build
args: --features async-native-tls,deprecated --package suppaftp
run: cargo build --features async-native-tls,deprecated --package suppaftp
- name: Build all features
uses: actions-rs/cargo@v1
with:
command: build
args: --features deprecated,native-tls,rustls,async-native-tls,async-rustls --package suppaftp
run: cargo build --features deprecated,native-tls,rustls,async-native-tls,async-rustls --package suppaftp
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --lib --package suppaftp --no-default-features --features rustls,native-tls,async-native-tls,async-rustls,with-containers --no-fail-fast
env:
RUST_LOG: trace
run: cargo test --lib --package suppaftp --no-default-features --features rustls,native-tls,async-native-tls,async-rustls,with-containers --no-fail-fast
- name: Format
run: cargo fmt --all -- --check
- name: Clippy
Expand Down
7 changes: 2 additions & 5 deletions .github/workflows/cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,13 @@ jobs:
working-directory: ./suppaftp-cli
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
override: true
components: rustfmt, clippy
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --package suppaftp-cli
run: cargo build --package suppaftp-cli
- name: Format
run: cargo fmt --all -- --check
- name: Clippy
Expand Down
9 changes: 3 additions & 6 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,14 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Setup containers
run: docker-compose -f "tests/docker-compose.yml" up -d --build
run: docker compose -f "tests/docker-compose.yml" up -d --build
- name: Setup nightly toolchain
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@stable
with:
toolchain: nightly
override: true
- name: Run tests (nightly)
uses: actions-rs/cargo@v1
with:
command: test
args: --lib --no-default-features --features native-tls,deprecated,async-native-tls,with-containers --no-fail-fast
run: cargo test --lib --package suppaftp --no-default-features --features native-tls,deprecated,async-native-tls,with-containers --no-fail-fast
env:
RUST_LOG: trace
CARGO_INCREMENTAL: "0"
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog

- [Changelog](#changelog)
- [6.0.2](#602)
- [6.0.1](#601)
- [6.0.0](#600)
- [5.4.0](#540)
Expand Down Expand Up @@ -34,6 +35,12 @@

---

## 6.0.2

Released on 14/10/2024

- [Issue 89](https://github.com/veeso/suppaftp/issues/89): added new `FtpStream::passive_stream_builder` to provide a function to build the Passive mode `TcpStream` with a custom builder. This is useful if you need to use some proxy.

## 6.0.1

Released on 24/05/2024
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ members = ["suppaftp", "suppaftp-cli"]
resolver = "2"

[workspace.package]
version = "6.0.1"
version = "6.0.2"
edition = "2021"
authors = [
"Christian Visintin <[email protected]>",
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</p>

<p align="center">Developed by <a href="https://veeso.github.io/">veeso</a> and <a href="https://github.com/mattnenterprise">Matt McCoy</a></p>
<p align="center">Current version: 6.0.1 (24/05/2024)</p>
<p align="center">Current version: 6.0.2 (14/10/2024)</p>

<p align="center">
<a href="https://opensource.org/licenses/MIT"
Expand Down
2 changes: 1 addition & 1 deletion suppaftp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ async-tls = { version = "^0.13", optional = true }
pin-project = { version = "^1", optional = true }
# secure
native-tls-crate = { package = "native-tls", version = "^0.2", optional = true }
rustls-crate = { package = "rustls", version = "^0.21", optional = true }
rustls-crate = { package = "rustls", version = "^0.23", optional = true }
futures-lite = "2.0.0"

[dev-dependencies]
Expand Down
59 changes: 53 additions & 6 deletions suppaftp/src/async_ftp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
mod data_stream;
mod tls;

use std::future::Future;
#[cfg(not(feature = "async-secure"))]
use std::marker::PhantomData;
use std::net::{Ipv4Addr, SocketAddr};
use std::pin::Pin;
use std::string::String;
use std::time::Duration;

Expand Down Expand Up @@ -35,6 +37,12 @@ use crate::command::Command;
use crate::command::ProtectionLevel;
use crate::types::Features;

/// A function that creates a new stream for the data connection in passive mode.
///
/// It takes a [`SocketAddr`] and returns a [`TcpStream`].
pub type PassiveStreamBuilder =
dyn Fn(SocketAddr) -> Pin<Box<dyn Future<Output = FtpResult<TcpStream>> + Send>>;

/// Stream to interface with the FTP server. This interface is only for the command stream.
pub struct ImplAsyncFtpStream<T>
where
Expand All @@ -45,6 +53,7 @@ where
nat_workaround: bool,
welcome_msg: Option<String>,
active_timeout: Duration,
passive_stream_builder: Box<PassiveStreamBuilder>,
#[cfg(not(feature = "async-secure"))]
marker: PhantomData<T>,
#[cfg(feature = "async-secure")]
Expand Down Expand Up @@ -85,6 +94,7 @@ where
marker: PhantomData {},
mode: Mode::Passive,
nat_workaround: false,
passive_stream_builder: Self::default_passive_stream_builder(),
welcome_msg: None,
#[cfg(feature = "async-secure")]
tls_ctx: None,
Expand Down Expand Up @@ -143,6 +153,7 @@ where
reader: BufReader::new(DataStream::Ssl(Box::new(stream))),
mode: self.mode,
nat_workaround: self.nat_workaround,
passive_stream_builder: self.passive_stream_builder,
tls_ctx: Some(Box::new(tls_connector)),
domain: Some(String::from(domain)),
welcome_msg: self.welcome_msg,
Expand Down Expand Up @@ -197,6 +208,7 @@ where
mode: Mode::Passive,
nat_workaround: false,
welcome_msg: None,
passive_stream_builder: Self::default_passive_stream_builder(),
tls_ctx: None,
domain: None,
active_timeout: Duration::from_secs(60),
Expand All @@ -213,6 +225,7 @@ where
reader: BufReader::new(DataStream::Ssl(stream.into())),
mode: Mode::Passive,
nat_workaround: false,
passive_stream_builder: Self::default_passive_stream_builder(),
tls_ctx: Some(Box::new(tls_connector)),
domain: Some(String::from(domain)),
welcome_msg: None,
Expand All @@ -238,6 +251,18 @@ where
self
}

/// Set a custom [`StreamBuilder`] for passive mode.
///
/// The stream builder is a function that takes a `SocketAddr` and returns a `TcpStream` and it's used
/// to create the [`TcpStream`] for the data connection in passive mode.
pub fn passive_stream_builder<F>(mut self, stream_builder: F) -> Self
where
F: Fn(SocketAddr) -> Pin<Box<dyn Future<Output = FtpResult<TcpStream>> + Send>> + 'static,
{
self.passive_stream_builder = Box::new(stream_builder);
self
}

/// Returns welcome message retrieved from server (if available)
pub fn get_welcome_msg(&self) -> Option<&str> {
self.welcome_msg.as_deref()
Expand Down Expand Up @@ -767,16 +792,12 @@ where
Mode::ExtendedPassive => {
let addr = self.epsv().await?;
self.perform(cmd).await?;
TcpStream::connect(addr)
.await
.map_err(FtpError::ConnectionError)?
(self.passive_stream_builder)(addr).await?
}
Mode::Passive => {
let addr = self.pasv().await?;
self.perform(cmd).await?;
TcpStream::connect(addr)
.await
.map_err(FtpError::ConnectionError)?
(self.passive_stream_builder)(addr).await?
}
};

Expand Down Expand Up @@ -1002,6 +1023,16 @@ where
self.finalize_retr_stream(data_stream).await?;
lines
}

fn default_passive_stream_builder() -> Box<PassiveStreamBuilder> {
Box::new(|address| {
Box::pin(async move {
TcpStream::connect(address)
.await
.map_err(FtpError::ConnectionError)
})
})
}
}

#[cfg(test)]
Expand Down Expand Up @@ -1400,6 +1431,22 @@ mod test {
finalize_stream(stream).await;
}

#[async_attributes::test]
async fn test_should_set_passive_stream_builder() {
crate::log_init();
let _ftp_stream = AsyncFtpStream::connect("test.rebex.net:21")
.await
.unwrap()
.passive_stream_builder(|addr| {
Box::pin(async move {
println!("Connecting to {}", addr);
TcpStream::connect(addr)
.await
.map_err(FtpError::ConnectionError)
})
});
}

// -- test utils

#[cfg(feature = "with-containers")]
Expand Down
Loading

0 comments on commit d328e6c

Please sign in to comment.