1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//!
//! Exposes a [Virtual File Systems (VFS)](https://docs.rs/vfs/) via HTTPS.
//!
//! The [HttpsFSServer] exposes a VFS (implementing [FileSystem](vfs::filesystem::FileSystem)) via HTTPS.
//! [HttpsFS] can be uses to access a [FileSystem](vfs::filesystem::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:
//! ```console
//! cargo run --example https_fs_server
//! ```
//!
//! Start the client side example in another terminal with:
//!
//! ```console
//! cargo run --example https_fs
//! ```
//!
//! ## Server side
//!
//! This example exposes a [memory file system](vfs::MemoryFS) via HTTPS. The content of the file system
//! is lost as soon as the server is terminated.
//!
//! ```no_run
//! # use vfs::MemoryFS;
//! # use vfs_https::{HttpsFSResult, HttpsFSServer};
//! #
//! # fn main() -> HttpsFSResult<()> {
//! // 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](vfs::filesystem::FileSystem) see the crate [vfs].
//! The crate [chrono] is used for the generation of the time stamp.
//!
//! ```no_run
//! # use chrono::prelude::*;
//! # use std::io::Read;
//! # use vfs::VfsPath;
//! # use vfs_https::HttpsFS;
//! #
//! # fn main() -> vfs::VfsResult<()> {
//! // 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);
//! #
//! # Ok(())
//! # }
//! ```
//!
//!
//! # TODOs
//! - Implement a [CGI](https://en.wikipedia.org/wiki/Common_Gateway_Interface)
//!   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

#![warn(missing_docs)]

mod error;
mod httpsfs;
mod protocol;
mod server;
pub use error::{HttpsFSError, HttpsFSResult};
pub use httpsfs::{HttpsFS, HttpsFSBuilder};
pub use server::{HttpsFSServer, HttpsFSServerBuilder};