Giter Site home page Giter Site logo

weihanglo / sfz Goto Github PK

View Code? Open in Web Editor NEW
398.0 5.0 30.0 1017 KB

A simple static file serving command-line tool written in Rust.

Home Page: https://crates.io/crates/sfz

License: Apache License 2.0

Rust 95.52% HTML 2.75% CSS 1.00% Ruby 0.74%
rust cli static-server

sfz's Introduction

Thank you for using this tool so far. Unfortunately I have no time maintaining it, but I believe people can find a better alternative out there on crates.io.

If you are still interested in supporting Rust and its community, please consider sponsoring Rust developers you like. You can find a few from the official Rust teams, or just buy me a coffee ❤️.

sfz

Crates.io Build Status Code Coverage Lines of Code Dependency Status

sfz, or Static File Zerver, is a simple command-line tool serving static files for you.

The name sfz is derived from an accented note Sforzando in music, which means “suddenly with force.”

Features

  • Directory listing
  • Partial responses (range requests)
  • Conditional requests with cache validations
  • Cross-origin resource sharing
  • Automatic HTTP compression (Brotli, Gzip, Deflate)
  • Automatic rendering index.html
  • Respect .gitignore file
  • Customize path prefix

Installation

Automatic

macOS

If you are a macOS Homebrew user, you can install sfz from a custom tap:

brew tap weihanglo/sfz https://github.com/weihanglo/sfz.git
brew install sfz

Disclaimer: Formula on Linuxbrew did not fully tested.

Cargo

If you are a Rust programmer, sfz are available on crates.io via Cargo.

cargo install sfz

You can also install the latest version (or a specific commit) of sfz directly from GitHub.

cargo install --git https://github.com/weihanglo/sfz.git

Manual

Prebuilt binaries

Archives of prebuilt binaries are available on GitHub Release for Linux, maxOS and Windows. Download a compatible binary for your system. For convenience, make sure you place sfz under $PATH if you want access it from the command line.

Build from source

sfz is written in Rust. You need to install Rust in order to compile it.

$ git clone https://github.com/weihanglo/sfz.git
$ cd sfz
$ cargo build --release
$ ./target/release/sfz --version
0.7.1

Usage

The simplest way to start serving files is to run this command:

sfz [FLAGS] [OPTIONS] [path]

The command above will start serving your current working directory on 127.0.0.1:5000 by default.

If you want to serve another directory, pass [path] positional argument in with either absolute or relaitve path.

sfz /usr/local

# Serve files under `/usr/local` directory.
# 
# You can press ctrl-c to exit immediately.

Flags and Options

sfz aims to be simple but configurable. Here is a list of available options:

USAGE:
    sfz [OPTIONS] [path]

ARGS:
    <path>    Path to a directory for serving files [default: .]

OPTIONS:
    -a, --all                   Serve hidden and dot (.) files
    -b, --bind <address>        Specify bind address [default: 127.0.0.1]
    -c, --cache <seconds>       Specify max-age of HTTP caching in seconds [default: 0]
    -C, --cors                  Enable Cross-Origin Resource Sharing from any origin (*)
        --coi                   Enable Cross-Origin isolation
    -h, --help                  Print help information
    -I, --no-ignore             Don't respect gitignore file
    -L, --follow-links          Follow symlinks outside current serving base path
        --no-log                Don't log any request/response information.
    -p, --port <port>           Specify port to listen on [default: 5000]
        --path-prefix <path>    Specify an url path prefix, helpful when running behing a reverse
                                proxy
    -r, --render-index          Render existing index.html when requesting a directory.
    -V, --version               Print version information
    -Z, --unzipped              Disable HTTP compression

Contributing

Contributions are highly appreciated! Feel free to open issues or send pull requests directly.

Credits

sfz was originally inspired by another static serving tool serve, and sfz's directory-listing UI is mainly borrowed from GitHub.

sfz is built on the top of awesome Rust community. Thanks for all Rust and crates contributors.

License

This project is licensed under either of

at your option.

Contribution

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

sfz's People

Contributors

cybai avatar henry40408 avatar jxs avatar lunar-mycroft avatar mu-arch avatar sy573m404 avatar weihanglo avatar whizsid avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

sfz's Issues

Log incoming requests

As a local server, it is expected to log any incoming requests while keeping information such as address and port statically on the screen simultaneously. Implementing with a scrollable list is better.

Improve brotli compression performance

There is significant performance loss in #97 when client requests brotli compression.

I'd like to find a way to improve it. At least make it as fast as commit 7113041.

Benchmark

master branch 7113041 feature/issue-33 2ee86cb
br Running 10s test @ http://localhost:5000/Cargo.toml
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 2.82ms 206.74us 11.20ms 86.73%
Req/Sec 1.78k 34.26 1.84k 83.50%
35471 requests in 10.00s, 54.16MB read
Requests/sec: 3545.80
Transfer/sec: 5.41MB
Running 10s test @ http://localhost:5000/Cargo.toml
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 5.50ms 2.16ms 26.19ms 71.38%
Req/Sec 0.92k 65.42 1.03k 78.50%
18233 requests in 10.01s, 17.01MB read
Requests/sec: 1821.76
Transfer/sec: 1.70MB

Option for catch-all redirect

When building a single page application is common to want all paths (that are not assets) to redirect to the root index.html

E.g.
/ -> /index.html
/users -> /index.html
/users/1 -> /index.html

The SPA handles the routing and shows the correct page. It would be great to have an option for this.

failed to run custom build command for `backtrace-sys v0.1.30`

➜  sfz git:(master) cargo check
    Checking rand_core v0.4.0
    Checking lazy_static v1.3.0
    Checking nodrop v0.1.13
    Checking stable_deref_trait v1.1.1
    Checking cfg-if v0.1.9
    Checking memoffset v0.2.1
    Checking smallvec v0.6.10
    Checking scopeguard v0.3.3
    Checking futures v0.1.28
    Checking slab v0.4.2
    Checking fnv v1.0.6
    Checking ucd-util v0.1.3
    Checking unic-char-range v0.7.0
    Checking matches v0.1.8
    Checking unic-common v0.7.0
    Checking adler32 v1.0.3
    Checking alloc-no-stdlib v2.0.1
    Checking rustc-demangle v0.1.15
    Checking utf8-ranges v1.0.3
    Checking siphasher v0.2.3
    Checking safemem v0.3.0
    Checking ucd-trie v0.1.1
    Checking itoa v0.4.4
    Checking same-file v1.0.4
    Checking unicode-width v0.1.5
    Checking try-lock v0.1.0
    Checking percent-encoding v1.0.1
    Checking scoped-tls v0.1.2
    Checking deunicode v0.4.3
    Checking glob v0.2.11
    Checking strsim v0.8.0
    Checking humansize v1.1.0
    Checking ansi_term v0.11.0
    Checking language-tags v0.2.2
    Checking log v0.4.6
    Checking owning_ref v0.4.0
    Checking crossbeam-utils v0.6.5
    Checking thread_local v0.3.6
    Checking unicode-bidi v0.3.4
    Checking unic-char-property v0.7.0
    Checking regex-syntax v0.6.8
    Checking unic-ucd-version v0.7.0
    Checking miniz_oxide v0.2.2
    Checking alloc-stdlib v0.2.1
    Checking rand_core v0.3.1
    Checking pest v2.1.1
    Checking walkdir v2.2.8
    Checking unicode-normalization v0.1.8
    Checking textwrap v0.11.0
    Checking libc v0.2.58
    Checking arrayvec v0.4.10
    Checking byteorder v1.3.2
    Checking slug v0.1.4
    Checking memchr v2.2.0
   Compiling backtrace-sys v0.1.30
error: failed to run custom build command for `backtrace-sys v0.1.30`

Caused by:
  process didn't exit successfully: `/Users/me/Documents/source/rust/sfz/target/debug/build/backtrace-sys-6c47ea0c6e530e8a/build-script-build` (exit code: 1)
--- stdout
cargo:rustc-cfg=rbt
TARGET = Some("x86_64-apple-darwin")
OPT_LEVEL = Some("0")
HOST = Some("x86_64-apple-darwin")
CC_x86_64-apple-darwin = None
CC_x86_64_apple_darwin = None
HOST_CC = None
CC = None
CFLAGS_x86_64-apple-darwin = None
CFLAGS_x86_64_apple_darwin = None
HOST_CFLAGS = None
CFLAGS = None
CRATE_CC_NO_DEFAULTS = None
CARGO_CFG_TARGET_FEATURE = Some("fxsr,sse,sse2,sse3,ssse3")
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-m64" "-I" "src/libbacktrace" "-I" "/Users/me/Documents/source/rust/sfz/target/debug/build/backtrace-sys-139583c10151832d/out" "-fvisibility=hidden" "-DBACKTRACE_SUPPORTED=1" "-DBACKTRACE_USES_MALLOC=1" "-DBACKTRACE_SUPPORTS_THREADS=0" "-DBACKTRACE_SUPPORTS_DATA=0" "-DHAVE_DL_ITERATE_PHDR=1" "-D_GNU_SOURCE=1" "-D_LARGE_FILES=1" "-Dbacktrace_full=__rbt_backtrace_full" "-Dbacktrace_dwarf_add=__rbt_backtrace_dwarf_add" "-Dbacktrace_initialize=__rbt_backtrace_initialize" "-Dbacktrace_pcinfo=__rbt_backtrace_pcinfo" "-Dbacktrace_syminfo=__rbt_backtrace_syminfo" "-Dbacktrace_get_view=__rbt_backtrace_get_view" "-Dbacktrace_release_view=__rbt_backtrace_release_view" "-Dbacktrace_alloc=__rbt_backtrace_alloc" "-Dbacktrace_free=__rbt_backtrace_free" "-Dbacktrace_vector_finish=__rbt_backtrace_vector_finish" "-Dbacktrace_vector_grow=__rbt_backtrace_vector_grow" "-Dbacktrace_vector_release=__rbt_backtrace_vector_release" "-Dbacktrace_close=__rbt_backtrace_close" "-Dbacktrace_open=__rbt_backtrace_open" "-Dbacktrace_print=__rbt_backtrace_print" "-Dbacktrace_simple=__rbt_backtrace_simple" "-Dbacktrace_qsort=__rbt_backtrace_qsort" "-Dbacktrace_create_state=__rbt_backtrace_create_state" "-Dbacktrace_uncompress_zdebug=__rbt_backtrace_uncompress_zdebug" "-Dmacho_get_view=__rbt_macho_get_view" "-Dmacho_symbol_type_relevant=__rbt_macho_symbol_type_relevant" "-Dmacho_get_commands=__rbt_macho_get_commands" "-Dmacho_try_dsym=__rbt_macho_try_dsym" "-Dmacho_try_dwarf=__rbt_macho_try_dwarf" "-Dmacho_get_addr_range=__rbt_macho_get_addr_range" "-Dmacho_get_uuid=__rbt_macho_get_uuid" "-Dmacho_add=__rbt_macho_add" "-Dmacho_add_symtab=__rbt_macho_add_symtab" "-Dmacho_file_to_host_u64=__rbt_macho_file_to_host_u64" "-Dmacho_file_to_host_u32=__rbt_macho_file_to_host_u32" "-Dmacho_file_to_host_u16=__rbt_macho_file_to_host_u16" "-o" "/Users/me/Documents/source/rust/sfz/target/debug/build/backtrace-sys-139583c10151832d/out/src/libbacktrace/alloc.o" "-c" "src/libbacktrace/alloc.c"
cargo:warning=src/libbacktrace/alloc.c:35:10: fatal error: 'errno.h' file not found
cargo:warning=#include <errno.h>
cargo:warning=         ^~~~~~~~~
cargo:warning=1 error generated.
exit code: 1

--- stderr


error occurred: Command "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-m64" "-I" "src/libbacktrace" "-I" "/Users/me/Documents/source/rust/sfz/target/debug/build/backtrace-sys-139583c10151832d/out" "-fvisibility=hidden" "-DBACKTRACE_SUPPORTED=1" "-DBACKTRACE_USES_MALLOC=1" "-DBACKTRACE_SUPPORTS_THREADS=0" "-DBACKTRACE_SUPPORTS_DATA=0" "-DHAVE_DL_ITERATE_PHDR=1" "-D_GNU_SOURCE=1" "-D_LARGE_FILES=1" "-Dbacktrace_full=__rbt_backtrace_full" "-Dbacktrace_dwarf_add=__rbt_backtrace_dwarf_add" "-Dbacktrace_initialize=__rbt_backtrace_initialize" "-Dbacktrace_pcinfo=__rbt_backtrace_pcinfo" "-Dbacktrace_syminfo=__rbt_backtrace_syminfo" "-Dbacktrace_get_view=__rbt_backtrace_get_view" "-Dbacktrace_release_view=__rbt_backtrace_release_view" "-Dbacktrace_alloc=__rbt_backtrace_alloc" "-Dbacktrace_free=__rbt_backtrace_free" "-Dbacktrace_vector_finish=__rbt_backtrace_vector_finish" "-Dbacktrace_vector_grow=__rbt_backtrace_vector_grow" "-Dbacktrace_vector_release=__rbt_backtrace_vector_release" "-Dbacktrace_close=__rbt_backtrace_close" "-Dbacktrace_open=__rbt_backtrace_open" "-Dbacktrace_print=__rbt_backtrace_print" "-Dbacktrace_simple=__rbt_backtrace_simple" "-Dbacktrace_qsort=__rbt_backtrace_qsort" "-Dbacktrace_create_state=__rbt_backtrace_create_state" "-Dbacktrace_uncompress_zdebug=__rbt_backtrace_uncompress_zdebug" "-Dmacho_get_view=__rbt_macho_get_view" "-Dmacho_symbol_type_relevant=__rbt_macho_symbol_type_relevant" "-Dmacho_get_commands=__rbt_macho_get_commands" "-Dmacho_try_dsym=__rbt_macho_try_dsym" "-Dmacho_try_dwarf=__rbt_macho_try_dwarf" "-Dmacho_get_addr_range=__rbt_macho_get_addr_range" "-Dmacho_get_uuid=__rbt_macho_get_uuid" "-Dmacho_add=__rbt_macho_add" "-Dmacho_add_symtab=__rbt_macho_add_symtab" "-Dmacho_file_to_host_u64=__rbt_macho_file_to_host_u64" "-Dmacho_file_to_host_u32=__rbt_macho_file_to_host_u32" "-Dmacho_file_to_host_u16=__rbt_macho_file_to_host_u16" "-o" "/Users/me/Documents/source/rust/sfz/target/debug/build/backtrace-sys-139583c10151832d/out/src/libbacktrace/alloc.o" "-c" "src/libbacktrace/alloc.c" with args "cc" did not execute successfully (status code exit code: 1).



warning: build failed, waiting for other jobs to finish...
error: build failed

Support files exclusion

It is helpful to exclude files to be served as an option.

This feature should

  • Respect to .gitignore or other ignore-files.
  • Provide a feature not to list hidden files is in demand.

In order to respect ignore-files, Ripgrep use ignore crate to build a directories walker respecting ignore-files.

Note that at present it only repects .gitignore file under the base path of directory served to reduce response latency.

If possible, ship the feature with some command-line options is welcome. Such as

  • --no-ignore to ignore .gitignore.
  • --no-hidden-files to unlist hidden files.

Prefer error propagation to explicit unwrapping

Currently, this project uses many explicit unwrapping in its codebase. That's not a healthy condition for a production. There is a useful crate error-chain for us to handle error more elegantly.

That is to say, we need to introduce error-chain to define our own error types as well as handle error conversions between ours and others.

Redirect with trailing slashes

If the user requests a page /foo/bar but sfz (with -r) renders /foo/bar/index.html, it should first redirect the user permanently to /foo/bar/.

This is consistent with most HTTP server implementationns. Lack of this redirection may lead to relative path resolution issues, especially when serving generated docs (e.g. rustdoc).

sfz might fail on test 'path_is_not_relatively_hidden' for no good reason?

Hi there!

I was trying to build sfz on Arch Linux (using this source package) with an AUR helper (`yay), but this single test was failing for me:

$ export RUST_BACKTRACE=1
$ yay -S sfz
[... suppressed output ...]
==> Starting check()...
[... suppressed output ...]
failures:

---- extensions::t_extensions::path_is_not_relatively_hidden stdout ----
thread 'extensions::t_extensions::path_is_not_relatively_hidden' panicked at 'assertion failed: !file_txt_path().is_relatively_hidden()', src/extensions.rs:146:9
stack backtrace:
   0: rust_begin_unwind
             at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/std/src/panicking.rs:493:5
   1: core::panicking::panic_fmt
             at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/core/src/panicking.rs:92:14
   2: core::panicking::panic
             at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/core/src/panicking.rs:50:5
   3: sfz::extensions::t_extensions::path_is_not_relatively_hidden
   4: core::ops::function::FnOnce::call_once
             at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.


failures:
    extensions::t_extensions::path_is_not_relatively_hidden

test result: FAILED. 69 passed; 1 failed; 3 ignored; 0 measured; 0 filtered out; finished in 0.01s

error: test failed, to rerun pass '--bin sfz'
==> ERROR: A failure occurred in check().
    Aborting...

At first, I thought it was a yay bug, since I was able to build that exact same package using only makepkg -s.

But as pointed out by someone else, the test fails because yay builds sfz under the ~/.cache directory.

While reproducing the issue, I then learned sfz will fail some other tests too

$ cd ~/.cache
$ git clone https://github.com/weihanglo/sfz.git
$ cd sfz/
$ export RUST_BACKTRACE=1
$ cargo test --release --locked
   Compiling cfg-if v1.0.0
   Compiling proc-macro2 v1.0.24
   Compiling libc v0.2.86
   Compiling autocfg v1.0.1
   Compiling memchr v2.3.4
   Compiling unicode-xid v0.2.1
   Compiling syn v1.0.60
   Compiling log v0.4.14
   Compiling fnv v1.0.7
   Compiling version_check v0.9.2
   Compiling once_cell v1.5.2
   Compiling itoa v0.4.7
   Compiling getrandom v0.2.2
   Compiling typenum v1.12.0
   Compiling lazy_static v1.4.0
   Compiling regex-syntax v0.6.22
   Compiling bitflags v1.2.1
   Compiling ucd-trie v0.1.3
   Compiling bytes v1.0.1
   Compiling serde_derive v1.0.123
   Compiling maplit v1.0.2
   Compiling ryu v1.0.5
   Compiling unic-common v0.9.0
   Compiling byteorder v1.4.2
   Compiling serde v1.0.123
   Compiling unic-char-range v0.9.0
   Compiling ppv-lite86 v0.2.10
   Compiling same-file v1.0.6
   Compiling crc32fast v1.2.1
   Compiling pin-project-lite v0.2.4
   Compiling byte-tools v0.3.1
   Compiling futures-core v0.3.12
   Compiling serde_json v1.0.62
   Compiling adler32 v1.2.0
   Compiling httparse v1.3.5
   Compiling alloc-no-stdlib v2.0.1
   Compiling deunicode v0.4.3
   Compiling cfg-if v0.1.10
   Compiling futures-task v0.3.12
   Compiling unicode-width v0.1.8
   Compiling mime v0.3.16
   Compiling fake-simd v0.1.2
   Compiling percent-encoding v2.1.0
   Compiling pin-utils v0.1.0
   Compiling opaque-debug v0.2.3
   Compiling try-lock v0.2.3
   Compiling humansize v1.1.0
   Compiling tower-service v0.3.1
   Compiling httpdate v0.3.2
   Compiling remove_dir_all v0.5.3
   Compiling base64 v0.13.0
   Compiling num-traits v0.2.14
   Compiling num-integer v0.1.44
   Compiling crossbeam-utils v0.8.1
   Compiling tokio v1.2.0
   Compiling thread_local v1.1.3
   Compiling tracing-core v0.1.17
   Compiling unicase v2.6.0
   Compiling pest v2.1.3
   Compiling http v0.2.3
   Compiling unic-ucd-version v0.9.0
   Compiling unic-char-property v0.9.0
   Compiling walkdir v2.3.1
   Compiling block-padding v0.1.5
   Compiling futures-channel v0.3.12
   Compiling miniz_oxide v0.3.7
   Compiling alloc-stdlib v0.2.1
   Compiling slug v0.1.4
   Compiling textwrap v0.11.0
   Compiling qstring v0.7.2
   Compiling futures-util v0.3.12
   Compiling tracing v0.1.24
   Compiling pest_meta v2.1.3
   Compiling unic-ucd-segment v0.9.0
   Compiling headers-core v0.2.0
   Compiling http-body v0.4.0
   Compiling brotli-decompressor v2.3.1
   Compiling aho-corasick v0.7.15
   Compiling bstr v0.2.15
   Compiling time v0.1.43
   Compiling socket2 v0.3.19
   Compiling quote v1.0.9
   Compiling mio v0.7.8
   Compiling want v0.3.0
   Compiling clap v2.33.3
   Compiling flate2 v1.0.14
   Compiling generic-array v0.12.3
   Compiling unic-segment v0.9.0
   Compiling brotli v3.3.0
   Compiling regex v1.4.3
   Compiling rand_core v0.6.2
   Compiling mime_guess v2.0.3
   Compiling digest v0.8.1
   Compiling block-buffer v0.7.3
   Compiling parse-zoneinfo v0.3.0
   Compiling globset v0.4.6
   Compiling rand_chacha v0.3.0
   Compiling pest_generator v2.1.3
   Compiling tokio-macros v1.1.0
   Compiling thiserror-impl v1.0.23
   Compiling pin-project-internal v1.0.5
   Compiling chrono v0.4.19
   Compiling sha-1 v0.8.2
   Compiling chrono-tz v0.5.3
   Compiling ignore v0.4.17
   Compiling rand v0.8.3
   Compiling pest_derive v2.1.0
   Compiling thiserror v1.0.23
   Compiling headers v0.3.3
   Compiling pin-project v1.0.5
   Compiling globwalk v0.8.1
   Compiling tempfile v3.2.0
   Compiling zip v0.5.10
   Compiling hyper v0.14.4
   Compiling tera v1.6.1
   Compiling sfz v0.4.0 (/home/gui/.cache/sfz)
    Finished release [optimized] target(s) in 2m 02s
     Running target/release/deps/sfz-1920102d9b28e947

running 73 tests
test cli::args::t::parse_addresses ... ok
test cli::app::t::get_matches ... ok
test cli::args::t::parse_absolute_path ... ok
test extensions::t_extensions::mime_is_compressed ... ok
test extensions::t_extensions::path_filename_str ... ok
test cli::args::t::parse_relative_path ... ok
test extensions::t_extensions::path_is_relatively_hidden ... ok
test extensions::t_extensions::path_mime ... ok
test extensions::t_extensions::path_mtime ... ignored
test cli::args::t::parse_default ... ok
test extensions::t_extensions::path_size ... ok
test extensions::t_extensions::system_time_to_timestamp ... ok
test extensions::t_extensions::path_type_ ... ok
test http::conditional_requests::t_fresh::no_precondition_header_fields ... ok
test http::conditional_requests::t_fresh::if_none_match_precedes_if_modified_since ... ok
test http::conditional_requests::t_fresh::only_if_modified_since ... ok
test http::conditional_requests::t_precondition::failed_with_if_match_not_passes ... ok
test http::conditional_requests::t_precondition::failed_with_if_unmodified_since_not_passes ... ok
test http::conditional_requests::t_precondition::ok_without_any_precondition ... ok
test http::conditional_requests::t_precondition::with_if_match_passes ... ok
test http::conditional_requests::t_precondition::with_if_unmodified_since_passes ... ok
test http::content_encoding::t_compress::failed ... ok
test http::content_encoding::t_parse_qvalue::parse_successfully ... ok
test http::content_encoding::t_prior::filter_out_zero_quality ... ok
test http::content_encoding::t_prior::pick_highest_priority ... ok
test http::content_encoding::t_prior::with_unsupported_encoding ... ok
test http::content_encoding::t_sort::same_qualities ... ok
test http::content_encoding::t_sort::second_item_with_greater_quality ... ok
test http::range_requests::t_range::no_if_range_header ... ok
test http::range_requests::t_range::no_range_header ... ok
test http::range_requests::t_range::only_accept_exact_match_mtime ... ok
test http::range_requests::t_range::strong_validator ... ok
test http::range_requests::t_range::weak_validator_as_falsy ... ok
test http::range_requests::t_satisfiable::multiple_byte_ranges ... ok
test http::range_requests::t_satisfiable::one_satisfiable_byte_range ... ok
test http::range_requests::t_satisfiable::one_unsatisfiable_byte_range ... ok
test http::range_requests::t_satisfiable::zero_byte_range ... ok
test http::content_encoding::t_compress::compressed ... ok
test server::res::t::response_304 ... ok
test server::res::t::response_404 ... ok
test server::res::t::response_403 ... ok
test server::res::t::response_412 ... ok
test server::res::t::response_500 ... ok
test server::send::t::breadcrumbs ... ok
test server::send::t::breadcrumbs_from_root ... ok
test server::send::t::breadcrumbs_with_slashes ... ok
test server::send::t::prefixed_breadcrumbs ... ok
test server::send::t_send::t_send_dir ... ignored
test server::send::t_send::t_send_dir_as_zip ... ok
test server::send::t_send::t_send_file_not_found ... ok
test server::send::t_send::t_send_file_success ... ok
test server::send::t_send::t_send_file_with_range_invalid_range ... ok
test server::send::t::render_successfully ... ok
test server::send::t_send::t_send_file_with_range_not_found ... ok
test server::send::t_send::t_send_file_with_range_multiple_bytes ... ok
test server::send::t_send::t_send_file_with_range_one_byte ... ok
test server::serve::t_server::can_compress ... ok
test server::serve::t_server::disable_cors ... ok
test server::serve::t_server::cannot_compress ... ok
test server::serve::t_server::enable_cache_control ... ok
test server::serve::t_server::enable_cors ... ok
test server::serve::t_server::file_path_from_path ... ok
test server::serve::t_server::guess_path_mime ... ok
test server::serve::t_server::handle_request ... ignored
test server::serve::t_server::path_exists ... ok
test server::serve::t_server::path_does_not_exists ... ok
test server::serve::t_server::path_is_hidden ... ok
test server::serve::t_server::path_is_ignored ... ok
test server::serve::t_server::path_is_not_hidden ... ok
test server::serve::t_server::path_is_under_basepath ... ok
test server::serve::t_server::strips_path_prefix ... ok
test server::serve::t_server::path_is_not_ignored ... ok
test extensions::t_extensions::path_is_not_relatively_hidden ... FAILED

failures:

---- extensions::t_extensions::path_is_not_relatively_hidden stdout ----
thread 'extensions::t_extensions::path_is_not_relatively_hidden' panicked at 'assertion failed: !file_txt_path().is_relatively_hidden()', src/extensions.rs:146:9
stack backtrace:
   0: rust_begin_unwind
             at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/std/src/panicking.rs:493:5
   1: core::panicking::panic_fmt
             at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/core/src/panicking.rs:92:14
   2: core::panicking::panic
             at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/core/src/panicking.rs:50:5
   3: sfz::extensions::t_extensions::path_is_not_relatively_hidden
   4: core::ops::function::FnOnce::call_once
             at /rustc/cb75ad5db02783e8b0222fee363c5f63f7e2cf5b/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.


failures:
    extensions::t_extensions::path_is_not_relatively_hidden

test result: FAILED. 69 passed; 1 failed; 3 ignored; 0 measured; 0 filtered out; finished in 0.01s

error: test failed, to rerun pass '--bin sfz'

Is this behavior expected?

Thank you.

Support HTTP compression

Compressing payload is one of the most important ways to improve the website performance. To be a great static file server, it must utilize compression algorithms in order to transfer contents more efficiently. Here are some modern, widely-used compression algorithms it must support:

To support HTTP compression, it must

  • Recognize Accept-Encoding header field.
  • Respond with Content-Encoding header field.
  • Respond with Vary header field in order to inform agent to cache correct representations.

Here are some great crates that seem very helpful.

🥇 use sfz to serve static file in porduction stage 🚀

Hi everyone !
it is my pleasure to thank you for your fantastic repo, actually I start using sfz in Experiment purpose behind Nginx Reverse Proxy for serve static file like single page application by using container and share sfz builder and make it as runtime for other container .It work fine for me !, it will be alternative to pm2,serve for me

so, my question is!, is safe to use sfz tool in production stage ?

Proper logging

Proposal

We should use nginx default combined log format. Since nginx is widely used nowadays and many logging services (I won't advertise them here) can parse nginx log messages without any configuration.

I extract the following log format from nginx 1.21.6 Docker image:

$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"

I ran a nginx Docker container on my laptop with the following command in sfz project directory:

docker run --rm -it -p 8080:80 -v $PWD:/usr/share/nginx/html nginx:1.21.6

...and the following curl command:

curl http://localhost:8080/Cargo.toml

...and I got the following log message in nginx Docker container:

172.17.0.1 - - [20/Sep/2022:12:03:29 +0000] "GET /Cargo.toml HTTP/1.1" 200 1535 "-" "curl/7.79.1" "-"

According to the same nginx documentation, I think that we should log the following information:

  • remote address
  • local time
  • HTTP method, path, query parameters and HTTP version
  • status code
  • bytes sent: since nginx supports compression, I will elaborate more in the following section

Out of Scope

I think maybe we can ignore the following segments for now since sfz usually runs locally:

  • HTTP Basic Auth username, denoted as $remote_user
  • HTTP referrer, denoted as $http_referrer
  • X-Forwarded-For, denoted as $http_x_forwarded_for

Other consideration

Compressed response body

Ordinary response body

I run the nginx Docker container with the following configuration to enable gzip:

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    gzip on;
    gzip_types text/html;
    gzip_disable "msie6";

    include /etc/nginx/conf.d/*.conf;
}

...and put the following HTML document under project directory (255 bytes):

<!DOCTYPE html>
<html lang="en">

<head>
  <title></title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link href="css/style.css" rel="stylesheet">
</head>

<body>
  <h1>Document</h1>
</body>

</html>

First curl command (without compression):

curl -v http://localhost:8080/
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.21.6
< Date: Tue, 20 Sep 2022 12:12:25 GMT
< Content-Type: text/html
< Content-Length: 255
< Last-Modified: Tue, 20 Sep 2022 12:09:08 GMT
< Connection: keep-alive
< ETag: "6329ad64-ff"
< Accept-Ranges: bytes
<
<!DOCTYPE html>
<html lang="en">

<head>
  <title></title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link href="css/style.css" rel="stylesheet">
</head>

<body>
  <h1>Document</h1>
</body>

</html>
* Connection #0 to host localhost left intact
curl http://localhost:8080/ | wc -c
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   255  100   255    0     0  20354      0 --:--:-- --:--:-- --:--:-- 85000
     255

...and get the following log message from nginx Docker container:

172.17.0.1 - - [20/Sep/2022:12:12:55 +0000] "GET / HTTP/1.1" 200 255 "-" "curl/7.79.1" "-"

Compressed response body

Same nginx configuration, same HTML document, different curl command:

curl -v --compressed http://localhost:8080/
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.79.1
> Accept: */*
> Accept-Encoding: deflate, gzip
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.21.6
< Date: Tue, 20 Sep 2022 12:15:15 GMT
< Content-Type: text/html
< Last-Modified: Tue, 20 Sep 2022 12:09:08 GMT
< Transfer-Encoding: chunked
< Connection: keep-alive
< ETag: W/"6329ad64-ff"
< Content-Encoding: gzip 👈 confirmed that gzip compression is enabled for this request
<
<!DOCTYPE html>
<html lang="en">

<head>
  <title></title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link href="css/style.css" rel="stylesheet">
</head>

<body>
  <h1>Document</h1>
</body>

</html>
* Connection #0 to host localhost left intact
curl --compressed -v http://localhost:8080/ | wc -c
*   Trying 127.0.0.1:8080...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.79.1
> Accept: */*
> Accept-Encoding: deflate, gzip
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.21.6
< Date: Tue, 20 Sep 2022 12:15:41 GMT
< Content-Type: text/html
< Last-Modified: Tue, 20 Sep 2022 12:09:08 GMT
< Transfer-Encoding: chunked
< Connection: keep-alive
< ETag: W/"6329ad64-ff"
< Content-Encoding: gzip
<
{ [209 bytes data]
100   198    0   198    0     0  13182      0 --:--:-- --:--:-- --:--:-- 39600
* Connection #0 to host localhost left intact
     255

...and I get the following log message from nginx Docker container:

172.17.0.1 - - [20/Sep/2022:12:15:41 +0000] "GET / HTTP/1.1" 200 209 "-" "curl/7.79.1" "-"

Noted that bytes sent by nginx now becomes 209 instead of 255, so it turns out nginx is able to calculate compressed response body and log it, which is the goal we were unable to achieve in #97.

I will try my best to collect compressed response body size so we can put it in log message.

Upgrade to hyper 0.13 (std::future::Future)

In Rust 1.36, Future is stabilized. Our dependency hyper have been upgrading to Future and async/await for a while. We should now wait for 1.39 to play with async/await in stable Rust.

How open to stylistic changes in the UI are we?

For example I wanted to add the ability to view more info like sizes, number of files, last edit times, alternate layout options, a slide out layout options panel, better mobile support, and previews. We could offer a flag like --simple or --advanced (depending on which version became default to show or hide the additional information.

Better integration

Hi, This is a nice tool. I'd like to integrate it with xplr. But as you can see, currently I have to use 2 workarounds:

  • Run on 0.0.0.0 and execute ip addr to get the IP address.
  • Use & and kill to manage the service as ctrl+c will exit out of xplr.

So, for better integration, is there any way we can find the print the actual system IP and map quit with some other key?

rust-analyzer catch tokio::main as error !

#[tokio::main(flavor = "current_thread")]

recently rust-analyzer catch tokio::main and show error message like, "proc macro "main" not expanded: Cannot create expander according to this issue ,my suggestion to change code to be

use tokio::main;

#[main(flavor = "current_thread")]
async fn main() {
       ....
}

Is it possible to set `charset` in content-type response header?

Hello there, thanks for the great application.
I am wondering if it is possible to set/add charset=utf-8 in Content-Type response header. Currently, I see the following type of text when I opening yaml file:

  workspace: # � todo �

but it is working well if I am replacing (via chrome extension) response header from Content-Type: text/x-yaml to Content-Type: text/x-yaml; charset utf-8.
Is it possible somehow to set up charset?
thanks in advance for your help and support

Path issues on Windows

sfz v0.3.0

Given the following directory structure:

foo/
  bar/
    blah.txt

I start the server in foo, and it correctly lists bar. I then click bar, and the URL becomes:

http://127.0.0.1:5000/foo\bar

Note the backslash between foo and bar. This request then also returns a 403 Forbidden. If I change the backslash to a forward slash, I instead get a 404 Not Found.

404 Not Found after two folders

Everything works fine. However once I go into two folders like localhost:5000/folder1/folder2 I get a 404 Not Found error for files and folders I want to access.

OS: Windows 10
Installed via cargo install sfz

Support auto-reload

Hope sfz supports auto-reload the page when the HTML files have been changed. 👏👏

Option for coop and coep headers

Several features of browser is not enabled due specture, unless a page declare itself as cross origin isolated by sending coop and coep headers to the browser. Notably, sharedArrayBuffer feature need those headers, which is required for testing rust programs with thread in web assembly. A --coi flag, similar to --cors that enables these headers would be great.

[Feature request] allow the usage of configuration files

It would be interesting if you could define a configuration file somewhere (eg. ~/.sfzconfig) so the user doesn't need to write all the flags all the time. I could help you with that if you want. It would be an interesting way to learn rust.

Can't serve files larger than available memory

I'm trying to download a single large (1.3GB) file from a DO droplet that has 0.8GB of free memory and the process is immediately killed by the scary oom_killer. This happens with both aria2c which tries a range request first and curl which doesn't, by default.

Using sfz-0.0.3-x86_64-unknown-linux-musl.tar.gz downloaded from the GitHub releases.

I'm happy to provide more details if you need anything else.

Content-type response header incorrect for .wasm

I've just started using sfz 0.6.1 for some WebAssembly development and I've noticed some odd behaviour.

When I request a .wasm file, sfz responds with content-type: application/wasm; charset=utf-8 but this isn't a utf-8 encoded file, it's a binary format. As a result when I try to load the WebAssembly in Firefox 92, it complains about the MIME type not being as expected and having to fallback to a slower instantiation method as a result.

`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:
 TypeError: WebAssembly: Response has unsupported MIME type 'application/wasm; charset=utf-8' expected 'application/wasm'

Here's a curl -v with sfz serving the file

*   Trying 127.0.0.1:5000...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET /pkg/web_rust_bg.wasm HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< server: sfz/0.6.1
< cache-control: public, max-age=0
< last-modified: Sat, 02 Oct 2021 14:34:33 GMT
< etag: "1633185273-23174"
< accept-ranges: bytes
< content-type: application/wasm; charset=utf-8
< content-length: 23174
< date: Sat, 02 Oct 2021 19:10:56 GMT
< 

For extra context, here's a curl -v with python3 -m http.server serving the file, which does not produce the error

*   Trying 127.0.0.1:8000...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8000 (#0)
> GET /pkg/web_rust_bg.wasm HTTP/1.1
> Host: 127.0.0.1:8000
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.8.10
< Date: Sat, 02 Oct 2021 19:11:38 GMT
< Content-type: application/wasm
< Content-Length: 23174
< Last-Modified: Sat, 02 Oct 2021 14:34:33 GMT
< 

CI/CD integration

If several unit tests are written, then introducing continuous integration for this project is appropriate.
Travis-CI and AppVeyor are two of the most popular CI/CD service providers. Should give them a try.

If we need some templates, give a look at trust.

render_index flag behaves weired

With -r flag, directory request gets a 404 error.

details

As description in help message, running with -r flag should enable rendering index.html for directory request. But with -r flag, can't get generated index.html.

Actually, render_index flag appends index.html to a requested directory path. - https://github.com/weihanglo/sfz/blob/master/src/server/mod.rs#L112
This behaviour will occur 404 error in https://github.com/weihanglo/sfz/blob/master/src/server/mod.rs#L214. So, It can not reach to send_dir function - sending rendered index - on https://github.com/weihanglo/sfz/blob/master/src/server/mod.rs#L229-L230.

support https

Simple https encryption with tempory generated certificate would be awesome.

Allow users to set user-defined style

Scenario

Sometimes I want to use sfz to display a list of files with long names.
I then use the browser's developer tools or edit style.css directly and re-build it to see the full file names.
To solve this problem, I initially thought that the number of columns and width should be configurable as command line options.
However, I felt that a more generic feature was needed to avoid the mass production of detailed front-end options in the future.

Suggestion

Add a --style <style> option to the command line so that user-defined css will work for file listing pages.

For example, use the following.

$ sfz -p 4000 --style 'li { width: 400px; }'

Remark

I have already implemented this feature in my fork.
If you feel this feature is a good one, I would like to submit a pull request.

Provide a basic authentication method

Sometimes people want to share files without exposing all file publicly. A basic authentication implementation is essential. We can do it with HTTP authentication described in RFC7235. Other configure-free solutions are also welcome.

Support basic HTTP response headers

As a simple static file server, providing additional information such as cache control in response headers is a must have. Some useful headers are listed below:

The task of applying these headers may separate to several subtasks. The urge is to detect a valid MIME type. We should implement MIME guessing first.

Allow BOTH listing and an index.html file to be the default view for a folder, with a combined mode for renderer and listing

Hello, I was testing in localhost some code and I executed sfz -Z -r, and it works for folders with an index.html. The command is also usefull because I can remove the -r flag and browse the folder in the browser. However, in this mode I cannot see the default index.htm, I have to manually open such file (eg: http://localhost:5000/something/index.html). It would be nice if there was a mode that showed the custom index.html in the directory and the file listing as a backup.

Thanks, and if it sounds interesting, I could help you add such feature.

:)

Basic command line interface and options

To be a human friendly command line tool. It must

  • Description of the tool and usage information.
  • Basic options such as determine port to listen on or files/directories to ignore.
  • Print out on which address and port we serve.
  • Easily copy address to system clipboard. Auto-copy is preferable.(not useful)
  • An interface to show incoming requests.

Range support off-by-one error

When the request header Range is set to bytes=0-, the last byte is missing from the response.

Reproduction steps

Create ohno.txt with contents:

$ printf "life" > ohno.txt
$ sfz -Z &
$ curl -s http://localhost:5000/ohno.txt; echo
[30/Jul/2020 18:08:59] "GET /ohno.txt" - 200 OK
life
$ curl -s http://localhost:5000/ohno.txt -H "Range: bytes=0-"; echo
[30/Jul/2020 18:09:16] "GET /ohno.txt" - 206 Partial Content
lif

Don't use echo to create ohno.txt, it would put a newline in it. Some text
editors also automatically insert newlines

Additional notes

The HTTP Range header is annoying to implement correctly, I recommend writing a bunch of tests around it!

I think just doing end - start + 1 here would fix it:

.take(end - start)

...but it's the end of the day and I'm tired, so.

Unit tests

Although this project is quite simple, it still needs some unit tests to validate all functionalities.

  • Command line arguments parsing.
  • Server integration tests.
  • Request processing
    • Conditional requests
    • Range requests
    • Precondition failure
    • Hidden and ignored paths.
    • Resources laid outside base path
    • Files/index.html reading.
  • Output of static page of directories
    • Data of directory listing items
    • Breadcrumb redirects items

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.