#https #expose #vfs #https-server #file #systems

vfs-https

Exposes a Virtual File Systems (VFS) via HTTPS

1 unstable release

0.1.0 Apr 11, 2021

#986 in Filesystem

Apache-2.0

69KB
1.5K SLoC

vfs-https

Exposes a Virtual File Systems (VFS) via HTTPS.

The [HttpsFSServer] exposes a VFS (implementing FileSystem) via HTTPS. [HttpsFS] can be uses to access a FileSystem exposed by a [HttpsFSServer].

Example

The two examples show the usage of a [HttpsFSServer] and a [HttpsFS]. It is assumed, that the examples are executed in the crate root. Therefore, you can find the referenced files in the crate repository.

Please note, that it is assumed, that the used certificate is issued for "localhost".

You can run the server side examples from the repository root with:

cargo run --example https_fs_server

Start the client side example in another terminal with:

cargo run --example https_fs

Server side

This example exposes a memory file system via HTTPS. The content of the file system is lost as soon as the server is terminated.

// Create a file system, which the server uses to access the files.
let fs = MemoryFS::new();

let server = HttpsFSServer::builder(fs)
    // Since this test will not be executed as super user, we are not allowed to listen on
    // a TCP port below 1000, such as the https port 443. Therefore we use a different port.
    .set_port(8443)
    // It is a https server, therefore we need to load a certificate, which the server
    // uses. For the example we use a self signed certificate. If you want to know how to
    // create a self signed certificate, see "/examples/cert/create.sh".
    .load_certificates("examples/cert/cert.crt")
    // We also need to load the private key, which belongs to the certificate.
    .load_private_key("examples/cert/private-key.key")
    // The server needs to authenticate the clients. Therefore we have to provide a method
    // which // validates the user credentials. In this example, only the username 'user'
    // and the password 'pass' is accepted.
    // As authentication process, the 'Basic' method as defined by the
    // [RFC7617](https://tools.ietf.org/html/rfc7617) is used.
    .set_credential_validator(|username: &str, password: &str| {
        username == "user" && password == "pass"
    });

// Run the server. This call is blocking.
server.run()

Client side

This example connects to a [HttpsFSServer] and creates a file "example.txt" if it does not exists and appends a new line to it. Afterwards it reads the whole file and prints the content to stdout. As long as the server is not restarted, the output of this program will change with each call.

For the usage of FileSystem see the crate [vfs]. The crate [chrono] is used for the generation of the time stamp.

// You can not access the server from a different host, since the used certificate is issued
// for the localhost and you have to use https://localhost:8443 to access the server. You can
// also not use IPs, i.g. https://127.0.0.1:8443, since we didn't issue the certificate
// for the IP.
let builder = HttpsFS::builder("localhost")
    // Set the port used by the server. The default is 443.
    .set_port(8443)
    // Add the self signed certificate as root certificate. If we don't do this, the client
    // refuses to connect to the HttpsFSServer. If the server uses a certificate issued by
    // an official certificate authority, than we don't need to add an additional root
    // certificate.
    .add_root_certificate("examples/cert/cert.crt")
    // The client will use the following method to get credentials for the authentication.
    .set_credential_provider(|server_msg| {
        println!(
            "Server request authentification with message \"{}\".",
            server_msg
        );
        (String::from("user"), String::from("pass"))
    });
let root: VfsPath = builder.build()?.into();
let root = root.join("example.txt")?;

// make sure that the file exists
if !root.exists()? {
    root.create_file()?;
}

// add a new line to the file
let mut file = root.append_file()?;
let time = Local::now();
let line = format!("{}: Hello HttpsFS!\n", time);
file.write(line.as_bytes())?;

// open file reading
let file = root.open_file()?;

// One should really use a BufReader, which reads files in chunks of 8kb.
// The Read trait, issues a new request to the HttpsFSServer with each call,
// even if only on byte is read. The headers of the http-protocol needs
// several hundred bytes, which makes small reads inefficient.
let mut buffed_file = std::io::BufReader::new(file);

// read file content
let mut content = String::new();
buffed_file.read_to_string(&mut content)?;

println!("Content of example.txt: \n{}", content);

TODOs

  • Implement a CGI version of the HttpsFSServer.
    • This would allow a user to use any webserver provided by its favorite web-hoster as an infrastructure. The advantage is, that the web-hoster can overtake the certificate management, which is often perceived as a liability.
  • Write a HttpsFS version, which can be compiled to WebAssembly
  • Consider to provide an non-blocking version of HttpsFS
  • Do version check after connecting to a HttpsFSServer

License: Apache-2.0

Dependencies

~16–30MB
~570K SLoC