Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 50 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@

<div align="center">

[![Crates.io](https://img.shields.io/crates/v/http-server.svg)](https://crates.io/crates/http-server)
[![Documentation](https://docs.rs/http-server/badge.svg)](https://docs.rs/http-server)
![Build](https://github.com/http-server-rs/http-server/workflows/build/badge.svg)
![Clippy](https://github.com/http-server-rs/http-server/workflows/clippy/badge.svg)
![Formatter](https://github.com/http-server-rs/http-server/workflows/fmt/badge.svg)
![Tests](https://github.com/http-server-rs/http-server/workflows/test/badge.svg)
![Benchs](https://github.com/http-server-rs/http-server/workflows/bench/badge.svg)
[![Crates.io](https://img.shields.io/crates/v/http-server.svg)](https://crates.io/crates/http-server)
[![Documentation](https://docs.rs/http-server/badge.svg)](https://docs.rs/http-server)
![Build](https://github.com/http-server-rs/http-server/workflows/build/badge.svg)
![Clippy](https://github.com/http-server-rs/http-server/workflows/clippy/badge.svg)
![Formatter](https://github.com/http-server-rs/http-server/workflows/fmt/badge.svg)
![Tests](https://github.com/http-server-rs/http-server/workflows/test/badge.svg)
![Benches](https://github.com/http-server-rs/http-server/workflows/bench/badge.svg)

</div>

Expand Down Expand Up @@ -45,10 +45,12 @@ FLAGS:
--graceful-shutdown Waits for all requests to fulfill before shutting down the server
--gzip Enable GZip compression for HTTP Responses
--help Prints help information
--logger Prints HTTP request and response details to stdout
-l, --logger Prints HTTP request and response details to stdout
-q, --quiet Turns off stdout/stderr logging
--spa Route non-existent files to /index.html
--tls Enables HTTPS serving using TLS
-i, --index Route directories to index.html if present
-V, --version Prints version information
-q, --quiet Turns off stdout/stderr logging

OPTIONS:
-c, --config <config> Path to TOML configuration file
Expand All @@ -74,19 +76,21 @@ configurations will be used. You can always change this behavior by either
creating your own config with the [Configuration TOML](https://github.com/http-server-rs/http-server/blob/main/fixtures/config.toml) file
or by providing CLI arguments described in the [usage](#usage) section.

Name | Description | Default
--- | --- | ---
Host | Address to bind the server | `127.0.0.1`
Port | Port to bind the server | `7878`
Root Directory | The directory to serve files from | `CWD`
File Explorer UI | A File Explorer UI for the directory configured as the _Root Directory_ | Enabled
Configuration File | Specifies a configuration file. [Example](https://github.com/http-server-rs/http-server/blob/main/fixtures/config.toml) | Disabled
HTTPS (TLS) | HTTPS Secure connection configuration. Refer to [TLS (HTTPS)](https://github.com/http-server-rs/http-server#tls-https) reference | Disabled
CORS | Cross-Origin-Resource-Sharing headers support. Refer to [CORS](https://github.com/http-server-rs/http-server#cross-origin-resource-sharing-cors) reference | Disabled
Compression | GZip compression for HTTP Response Bodies. Refer to [Compression](https://github.com/http-server-rs/http-server#compression) reference | Disabled
Quiet | Don't print server details when running. This doesn't include any logging capabilities. | Disabled
Basic Authentication | Authorize requests using Basic Authentication. Refer to [Basic Authentication](https://github.com/http-server-rs/http-server#basic-authentication) | Disabled
Logger | Prints HTTP request and response details to stdout | Disabled
| Name | Description | Default |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| Host | Address to bind the server | `127.0.0.1` |
| Port | Port to bind the server | `7878` |
| Root Directory | The directory to serve files from | `CWD` |
| File Explorer UI | A File Explorer UI for the directory configured as the _Root Directory_ | Enabled |
| Configuration File | Specifies a configuration file. [Example](https://github.com/http-server-rs/http-server/blob/main/fixtures/config.toml) | Disabled |
| HTTPS (TLS) | HTTPS Secure connection configuration. Refer to [TLS (HTTPS)](https://github.com/http-server-rs/http-server#tls-https) reference | Disabled |
| CORS | Cross-Origin-Resource-Sharing headers support. Refer to [CORS](https://github.com/http-server-rs/http-server#cross-origin-resource-sharing-cors) reference | Disabled |
| Compression | GZip compression for HTTP Response Bodies. Refer to [Compression](https://github.com/http-server-rs/http-server#compression) reference | Disabled |
| Quiet | Don't print server details when running. This doesn't include any logging capabilities. | Disabled |
| Index | Route directories to index.html if present | Disabled |
| SPA | Route non-existent files to /index.html | Disabled |
| Basic Authentication | Authorize requests using Basic Authentication. Refer to [Basic Authentication](https://github.com/http-server-rs/http-server#basic-authentication) | Disabled |
| Logger | Prints HTTP request and response details to stdout | Disabled |

## Usage

Expand All @@ -102,15 +106,17 @@ Flags are provided without any values. For example:
http-server --help
```

Name | Short | Long | Description
--- | --- | --- | ---
Cross-Origin Resource Sharing | N/A | `--cors` | Enable Cross-Origin Resource Sharing allowing any origin
GZip Compression | N/A | `--gzip` | Enable GZip compression for responses
Graceful Shutdown | N/A | `--graceful-shutdown` | Wait for all requests to be fulfilled before shutting down the server
Help | N/A | `--help` | Print help information
Logger | `-l` | `--logger` | Print HTTP request and response details to stdout
Version | `-V` | `--version` | Print version information
Quiet | `-q` | `--quiet` | Don't print output to console
| Name | Short | Long | Description |
| ----------------------------- | ----- | --------------------- | --------------------------------------------------------------------- |
| Cross-Origin Resource Sharing | N/A | `--cors` | Enable Cross-Origin Resource Sharing allowing any origin |
| GZip Compression | N/A | `--gzip` | Enable GZip compression for responses |
| Graceful Shutdown | N/A | `--graceful-shutdown` | Wait for all requests to be fulfilled before shutting down the server |
| Help | N/A | `--help` | Print help information |
| Logger | `-l` | `--logger` | Print HTTP request and response details to stdout |
| Version | `-V` | `--version` | Print version information |
| Quiet | `-q` | `--quiet` | Don't print output to console |
| Index | `-i` | `--index` | Route directories to index.html if present |
| SPA | N/A | `--spa` | Route non-existent files to /index.html |

### Options

Expand All @@ -120,18 +126,18 @@ Options receive a value and support default values as well.
http-server --host 127.0.0.1
```

Name | Short | Long | Description | Default Value
--- | --- | --- | --- | ---
Host | `-h` | `--host` | Address to bind the server | `127.0.0.1`
Port | `-p` | `--port` | Port to bind the server | `7878`
Configuration File | `-c` | `--config` | Configuration file. [Example](https://github.com/http-server-rs/http-server/blob/main/fixtures/config.toml) | N/A
TLS | N/A | `--tls` | Enable TLS for HTTPS connections. Requires a Certificate and Key. [Reference](#tls-reference) | N/A
TLS Ceritificate | N/A | `--tls-cert` | Path to TLS certificate file. **Depends on `--tls`** | `cert.pem`
TLS Key | N/A | `--tls-key` | Path to TLS key file. **Depends on `--tls`** | `key.rsa`
TLS Key Algorithm | N/A | `--tls-key-algorithm` | Algorithm used to generate certificate key. **Depends on `--tls`** | `rsa`
Username | N/A | `--username` | Username to validate using basic authentication | N/A
Password | N/A | `--password` | Password to validate using basic authentication. **Depends on `--username`** | N/A
Proxy | N/A | `--proxy` | Proxy requests to the provided URL | N/A
| Name | Short | Long | Description | Default Value |
| ------------------ | ----- | --------------------- | ----------------------------------------------------------------------------------------------------------- | ------------- |
| Host | `-h` | `--host` | Address to bind the server | `127.0.0.1` |
| Port | `-p` | `--port` | Port to bind the server | `7878` |
| Configuration File | `-c` | `--config` | Configuration file. [Example](https://github.com/http-server-rs/http-server/blob/main/fixtures/config.toml) | N/A |
| TLS | N/A | `--tls` | Enable TLS for HTTPS connections. Requires a Certificate and Key. [Reference](#tls-reference) | N/A |
| TLS Certificate | N/A | `--tls-cert` | Path to TLS certificate file. **Depends on `--tls`** | `cert.pem` |
| TLS Key | N/A | `--tls-key` | Path to TLS key file. **Depends on `--tls`** | `key.rsa` |
| TLS Key Algorithm | N/A | `--tls-key-algorithm` | Algorithm used to generate certificate key. **Depends on `--tls`** | `rsa` |
| Username | N/A | `--username` | Username to validate using basic authentication | N/A |
| Password | N/A | `--password` | Password to validate using basic authentication. **Depends on `--username`** | N/A |
| Proxy | N/A | `--proxy` | Proxy requests to the provided URL | N/A |

## Request Handlers

Expand Down Expand Up @@ -285,7 +291,7 @@ open an issue to be assigned and track the progress there.

- [x] Logging
- [x] Request/Response Logging
- [x] Service Config Loggins
- [x] Service Config Logins
- [ ] File Explorer
- [x] Modified Date
- [x] File Size
Expand Down
2 changes: 2 additions & 0 deletions fixtures/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ port = 7878
# quiet = false
# root_dir = "./"
# graceful_shutdown = false
# index = false
# spa = false

# [tls]
# cert = "cert.pem"
Expand Down
92 changes: 71 additions & 21 deletions src/addon/file_server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ mod scoped_file_system;

use chrono::{DateTime, Local};

pub use file::File;
use humansize::{format_size, DECIMAL};

pub use scoped_file_system::{Entry, ScopedFileSystem};

use anyhow::{Context, Result};
Expand All @@ -20,6 +22,7 @@ use std::path::{Component, Path, PathBuf};
use std::str::FromStr;
use std::sync::Arc;

use crate::config::Config;
use crate::utils::url_encode::{decode_uri, encode_uri, PERCENT_ENCODE_SET};

use self::directory_entry::{BreadcrumbItem, DirectoryEntry, DirectoryIndex, Sort};
Expand All @@ -30,21 +33,21 @@ use self::query_params::{QueryParams, SortBy};
const EXPLORER_TEMPLATE: &str = "explorer";

pub struct FileServer {
root_dir: PathBuf,
handlebars: Arc<Handlebars<'static>>,
scoped_file_system: ScopedFileSystem,
config: Arc<Config>,
}

impl<'a> FileServer {
/// Creates a new instance of the `FileExplorer` with the provided `root_dir`
pub fn new(root_dir: PathBuf) -> Self {
pub fn new(config: Arc<Config>) -> Self {
let handlebars = FileServer::make_handlebars_engine();
let scoped_file_system = ScopedFileSystem::new(root_dir.clone()).unwrap();
let scoped_file_system = ScopedFileSystem::new(config.root_dir().clone()).unwrap();

FileServer {
root_dir,
handlebars,
scoped_file_system,
config,
}
}

Expand Down Expand Up @@ -128,33 +131,80 @@ impl<'a> FileServer {
/// If the matched path resolves to a file, attempts to render it if the
/// MIME type is supported, otherwise returns the binary (downloadable file)
pub async fn resolve(&self, req_path: String) -> Result<Response<Body>> {
use std::io::ErrorKind;

let (path, query_params) = FileServer::parse_path(req_path.as_str())?;

match self.scoped_file_system.resolve(path).await {
Ok(entry) => match entry {
Entry::Directory(dir) => {
if self.config.index() {
let mut filepath = dir.path();

filepath.push("index.html");
if let Ok(file) = tokio::fs::File::open(&filepath).await {
return make_http_file_response(
File {
path: filepath,
metadata: file.metadata().await?,
file,
},
CacheControlDirective::MaxAge(2500),
)
.await;
}
}

self.render_directory_index(dir.path(), query_params).await
}
Entry::File(file) => {
make_http_file_response(*file, CacheControlDirective::MaxAge(2500)).await
}
},
Err(err) => match err.kind() {
ErrorKind::NotFound => Ok(HttpResponseBuilder::new()
.status(StatusCode::NOT_FOUND)
.body(Body::from(err.to_string()))
.expect("Failed to build response")),
ErrorKind::PermissionDenied => Ok(HttpResponseBuilder::new()
.status(StatusCode::FORBIDDEN)
.body(Body::from(err.to_string()))
.expect("Failed to build response")),
_ => Ok(HttpResponseBuilder::new()
.status(StatusCode::BAD_REQUEST)
.body(Body::from(err.to_string()))
.expect("Failed to build response")),
},
Err(err) => {
if self.config.spa() {
return make_http_file_response(
{
let mut path = self.config.root_dir();
path.push("index.html");

let file = tokio::fs::File::open(&path).await?;

let metadata = file.metadata().await?;

File {
path,
metadata,
file,
}
},
CacheControlDirective::MaxAge(2500),
)
.await;
}

let status = match err.kind() {
std::io::ErrorKind::NotFound => hyper::StatusCode::NOT_FOUND,
std::io::ErrorKind::PermissionDenied => hyper::StatusCode::FORBIDDEN,
_ => hyper::StatusCode::BAD_REQUEST,
};

let code = match err.kind() {
std::io::ErrorKind::NotFound => "404",
std::io::ErrorKind::PermissionDenied => "403",
_ => "400",
};

let response = hyper::Response::builder()
.status(status)
.header(http::header::CONTENT_TYPE, "text/html")
.body(hyper::Body::from(
handlebars::Handlebars::new().render_template(
include_str!("./template/error.hbs"),
&serde_json::json!({"error": err.to_string(), "code": code}),
)?,
))?;

Ok(response)
}
}
}

Expand All @@ -167,7 +217,7 @@ impl<'a> FileServer {
query_params: Option<QueryParams>,
) -> Result<Response<Body>> {
let directory_index =
FileServer::index_directory(self.root_dir.clone(), path, query_params)?;
FileServer::index_directory(self.config.root_dir().clone(), path, query_params)?;
let html = self
.handlebars
.render(EXPLORER_TEMPLATE, &directory_index)
Expand Down
4 changes: 4 additions & 0 deletions src/addon/file_server/template/error.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<center>
<h1>{{code}}</h1>
<p>{{error}}</p>
</center>
Loading