21 stable releases

5.3.1 Jan 28, 2024
5.2.2 Nov 14, 2023
5.1.2 Jun 14, 2023
5.1.0 Mar 2, 2023
4.1.2 Aug 23, 2021

#34 in Network programming

Download history 7118/week @ 2023-12-23 9607/week @ 2023-12-30 11891/week @ 2024-01-06 12574/week @ 2024-01-13 11518/week @ 2024-01-20 11702/week @ 2024-01-27 10178/week @ 2024-02-03 7556/week @ 2024-02-10 10970/week @ 2024-02-17 9695/week @ 2024-02-24 7843/week @ 2024-03-02 8906/week @ 2024-03-09 10831/week @ 2024-03-16 8925/week @ 2024-03-23 9304/week @ 2024-03-30 8810/week @ 2024-04-06

39,409 downloads per month
Used in 29 crates (9 directly)

Apache-2.0

215KB
4K SLoC

SuppaFTP

logo

~ A super FTP/FTPS client library for Rust ~

Documentation ยท Crates.io

Developed by veeso and Matt McCoy

Current version: 5.3.0 (06/01/2024)

License-Apache-2.0/MIT Repo stars Downloads counter Latest version Ko-fi conventional-commits

Lib-CI Cli-bin-ci Coveralls Docs



Introduction ๐Ÿ‘‹

SuppaFTP is the main FTP/FTPS client library for Rust, with both support for sync/async programming and for all the FTP protocol features. It is a fork of the original ftp library "rust-ftp", but since the original library is currently unmaintained, I decided to keep working on this library by myself. Currently, I consider myself as the only maintainer of this project, indeed I've already added some features to the library and improved it with better error handling and test units.

Main differences between SuppaFTP and rust-ftp ๐Ÿค”

  • Replaced OpenSSL with native-tls or rustls as you prefer ๐Ÿ”’
  • Added methods to work with streams (e.g. put_with_stream) โฌ‡๏ธ
  • suppaftp supports Active mode
  • Added get_welcome_msg method ๐Ÿ‘‹
  • Supports for both sync/async rust ๐Ÿ•™
  • Supports for more commands ๐ŸŒŸ
    • ABOR
    • APPE
    • REST
    • EPSV
    • EPRT
  • Some extra features, such as the LIST command output parser
  • Implementation of RFC 2428
  • Implementationb of RFC 2389
  • Removed deprecated statements โšฐ๏ธ
  • Better error handling ๐Ÿ›
  • Added test units keeping an eye on code coverage ๐Ÿ‘€

Get started ๐Ÿ

To get started, first add suppaftp to your dependencies:

suppaftp = "^5.3.0"

Features

SSL/TLS Support

If you want to enable support for FTPS, you must enable the native-tls or rustls feature in your cargo dependencies, based on the TLS provider you prefer.

suppaftp = { version = "^5.3.0", features = ["native-tls"] }
# or
suppaftp = { version = "^5.3.0", features = ["rustls"] }

๐Ÿ’ก If you don't know what to choose, native-tls should be preferred for compatibility reasons. โ— If you want to link libssl statically, enable feature native-tls-vendored

Async support

If you want to enable async support, you must enable async feature in your cargo dependencies.

suppaftp = { version = "^5.2.0", features = ["async"] }

โš ๏ธ If you want to enable both native-tls and async you must use the async-native-tls feature โš ๏ธ โš ๏ธ If you want to enable both rustls and async you must use the async-rustls feature โš ๏ธ โ— If you want to link libssl statically, enable feature async-native-tls-vendored

Deprecated methods

If you want to enable deprecated methods of FTPS, please enable the deprecated feature in your cargo dependencies.

This feature enables these methods:

  • connect_secure_implicit(): used to connect via implicit FTPS

Logging

By default, the library will log if there is any log crate consumer on the user implementation. Logging can be if preferred, disabled via the no-log feature.

Examples ๐Ÿ“š

use std::str;
use std::io::Cursor;
use suppaftp::FtpStream;

fn main() {
    // Create a connection to an FTP server and authenticate to it.
    let mut ftp_stream = FtpStream::connect("127.0.0.1:21").unwrap();
    let _ = ftp_stream.login("username", "password").unwrap();

    // Get the current directory that the client will be reading from and writing to.
    println!("Current directory: {}", ftp_stream.pwd().unwrap());

    // Change into a new directory, relative to the one we are currently in.
    let _ = ftp_stream.cwd("test_data").unwrap();

    // Retrieve (GET) a file from the FTP server in the current working directory.
    let data = ftp_stream.retr_as_buffer("ftpext-charter.txt").unwrap();
    println!("Read file with contents\n{}\n", str::from_utf8(&data.into_inner()).unwrap());

    // Store (PUT) a file from the client to the current working directory of the server.
    let mut reader = Cursor::new("Hello from the Rust \"ftp\" crate!".as_bytes());
    let _ = ftp_stream.put_file("greeting.txt", &mut reader);
    println!("Successfully wrote greeting.txt");

    // Terminate the connection to the server.
    let _ = ftp_stream.quit();
}

Ftp with TLS (native-tls)

use suppaftp::{NativeTlsFtpStream, NativeTlsConnector};
use suppaftp::native_tls::{TlsConnector, TlsStream};

fn main() {
    let ftp_stream = NativeTlsFtpStream::connect("test.rebex.net:21").unwrap();
    // Switch to the secure mode
    let mut ftp_stream = ftp_stream.into_secure(NativeTlsConnector::from(TlsConnector::new().unwrap()), "test.rebex.net").unwrap();
    ftp_stream.login("demo", "password").unwrap();
    // Do other secret stuff
    assert!(ftp_stream.quit().is_ok());
}

Ftp with TLS (rustls)

use std::str;
use std::io::Cursor;
use std::sync::Arc;
use suppaftp::{RustlsFtpStream, RustlsConnector};
use suppaftp::rustls::ClientConfig;

fn main() {
    let mut root_store = rustls::RootCertStore::empty();
    root_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| {
        rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
            ta.subject,
            ta.spki,
            ta.name_constraints,
        )
    }));
    let config = ClientConfig::builder()
        .with_safe_defaults()
        .with_root_certificates(root_store)
        .with_no_client_auth();
    // Create a connection to an FTP server and authenticate to it.
    let config = Arc::new(rustls_config());
    let mut ftp_stream = RustlsFtpStream::connect("test.rebex.net:21")
        .unwrap()
        .into_secure(RustlsConnector::from(Arc::clone(&config)), "test.rebex.net")
        .unwrap();
    // Terminate the connection to the server.
    let _ = ftp_stream.quit();
}

Going Async

use suppaftp::{AsyncNativeTlsFtpStream, AsyncNativeTlsConnector};
use suppaftp::async_native_tls::{TlsConnector, TlsStream};
let ftp_stream = AsyncNativeFtpStream::connect("test.rebex.net:21").await.unwrap();
// Switch to the secure mode
let mut ftp_stream = ftp_stream.into_secure(AsyncNativeTlsConnector::from(TlsConnector::new()), "test.rebex.net").await.unwrap();
ftp_stream.login("demo", "password").await.unwrap();
// Do other secret stuff
assert!(ftp_stream.quit().await.is_ok());

Built-in CLI client ๐Ÿ–ฅ๏ธ

SuppaFTP comes also with a built-in command-line FTP client. This CLI application provides all the commands to interact with a remote FTP server and supports FTPS too. You can also use it as a reference to implement your project. You can find it in the cli/ directory.

You can simply install as any other rust application via Cargo:

cargo install suppaftp-cli
suppaftp --version

Support the developer โ˜•

If you like SuppaFTP, please consider a little donation ๐Ÿฅณ

ko-fi PayPal


Changelog โŒ›

View Changelog here


License ๐Ÿ“œ

Licensed under either of

at your option.


Contribution ๐Ÿค

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

If you want to contribute to this project, please read the Contributing guide first ๐Ÿ™‚.

Dependencies

~4โ€“18MB
~251K SLoC