From efb2c0cd8a14391c615cf1e6314fc82f3d8b0b39 Mon Sep 17 00:00:00 2001 From: Jose Quintana <1700322+joseluisq@users.noreply.github.com> Date: Mon, 9 Oct 2023 03:25:27 +0200 Subject: [PATCH] Multiple index files support (#267) * feat: multiple index files support option: --index-files="a.html, b.htm, etc" env: SERVER_INDEX_FILES default value: "index.html" --- README.md | 1 + docs/content/configuration/command-line-arguments.md | 2 ++ docs/content/configuration/config-file.md | 3 +++ docs/content/configuration/environment-variables.md | 3 +++ docs/content/features/multiple-index-files.md | 17 +++++++++++++++++ docs/content/index.md | 1 + docs/mkdocs.yml | 1 + src/handler.rs | 5 +++++ src/server.rs | 13 +++++++++++++ src/settings/cli.rs | 5 +++++ src/settings/file.rs | 3 +++ src/settings/mod.rs | 5 +++++ src/static_files.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- tests/compression_static.rs | 3 +++ tests/dir_listing.rs | 14 +++++++++++--- tests/fixtures/public/index.htm | 1 + tests/static_files.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/toml/config.toml | 3 +++ 18 files changed, 207 insertions(+), 35 deletions(-) create mode 100644 docs/content/features/multiple-index-files.md create mode 100644 tests/fixtures/public/index.htm diff --git a/README.md b/README.md index fb06318..b3144b4 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ Cross-platform and available for `Linux`, `macOS`, `Windows`, `FreeBSD`, `NetBSD - Support for serving pre-compressed (Gzip/Brotli/Zstd) files directly from disk. - Custom URL rewrites and redirects via glob patterns with replacements. - Virtual hosting support. +- Multiple index files. - Available as a library crate with opt-in features. - First-class [Docker](https://docs.docker.com/get-started/overview/) support. [Scratch](https://hub.docker.com/_/scratch), latest [Alpine Linux](https://hub.docker.com/_/alpine) and [Debian](https://hub.docker.com/_/alpine) Docker images. - Ability to accept a socket listener as a file descriptor for sandboxing and on-demand applications (e.g. [systemd](http://0pointer.de/blog/projects/socket-activation.html)). diff --git a/docs/content/configuration/command-line-arguments.md b/docs/content/configuration/command-line-arguments.md index cea36a4..3d740c6 100644 --- a/docs/content/configuration/command-line-arguments.md +++ b/docs/content/configuration/command-line-arguments.md @@ -55,6 +55,8 @@ Options: HTTP host port where the redirect server will listen for requests to redirect them to HTTPS. It depends on "https_redirect" to be enabled [env: SERVER_HTTPS_REDIRECT_FROM_PORT=] [default: 80] --https-redirect-from-hosts List of host names or IPs allowed to redirect from. HTTP requests must contain the HTTP 'Host' header and match against this list. It depends on "https_redirect" to be enabled [env: SERVER_HTTPS_REDIRECT_FROM_HOSTS=] [default: localhost] + --index-files + List of files that will be used as an index for requests ending with the slash character (‘/’). Files are checked in the specified order [env: SERVER_INDEX_FILES=] [default: index.html] -x, --compression[=] Gzip, Deflate, Brotli or Zstd compression on demand determined by the Accept-Encoding header and applied to text-based web file types only [env: SERVER_COMPRESSION=] [default: true] [possible values: true, false] --compression-static[=] diff --git a/docs/content/configuration/config-file.md b/docs/content/configuration/config-file.md index 0e8362e..b5c3a43 100644 --- a/docs/content/configuration/config-file.md +++ b/docs/content/configuration/config-file.md @@ -78,6 +78,9 @@ compression-static = true #### Health-check endpoint (GET or HEAD `/health`) health = false +#### List of index files +# index-files = "index.html, index.htm" + ### Windows Only #### Run the web server as a Windows Service diff --git a/docs/content/configuration/environment-variables.md b/docs/content/configuration/environment-variables.md index 0eb3b47..4a804e1 100644 --- a/docs/content/configuration/environment-variables.md +++ b/docs/content/configuration/environment-variables.md @@ -108,6 +108,9 @@ Ignore hidden files/directories (dotfiles), preventing them to be served and bei ### SERVER_HEALTH Activate the health endpoint. +### SERVER_INDEX_FILES +List of files that will be used as an index for requests ending with the slash character (‘/’). Files are checked in the specified order. Default `index.html`. + ## Windows The following options and commands are Windows platform-specific. diff --git a/docs/content/features/multiple-index-files.md b/docs/content/features/multiple-index-files.md new file mode 100644 index 0000000..65cf85c --- /dev/null +++ b/docs/content/features/multiple-index-files.md @@ -0,0 +1,17 @@ +# Multiple index files + +**`SWS`** allows to provide a list of files that will be used as an index for requests ending with the slash character (‘/’). + +!!! info "Notes" + - Files are checked in the specified order from left to right. + - The option value can be a single index or comma-separated when multiple values. + - The default value is `index.html`. + +This feature is disabled by default and can be controlled by the string list `--index-files` option or the equivalent [SERVER_INDEX_FILES](./../configuration/environment-variables.md#server_index_files) env. + +Here is an example: + +```sh +static-web-server -p 8787 -d ./public \ + --index-files="index.html, index.htm, default.html" +``` diff --git a/docs/content/index.md b/docs/content/index.md index 7f6d4b5..47e1d63 100644 --- a/docs/content/index.md +++ b/docs/content/index.md @@ -69,6 +69,7 @@ Cross-platform and available for `Linux`, `macOS`, `Windows`, `FreeBSD`, `NetBSD - Support for serving pre-compressed (Gzip/Brotli/Zstd) files directly from disk. - Custom URL rewrites and redirects via glob patterns with replacements. - Virtual hosting support. +- Multiple index files. - Available as a library crate with opt-in features. - First-class [Docker](https://docs.docker.com/get-started/overview/) support. [Scratch](https://hub.docker.com/_/scratch), latest [Alpine Linux](https://hub.docker.com/_/alpine) and [Debian](https://hub.docker.com/_/alpine) Docker images. - Ability to accept a socket listener as a file descriptor for sandboxing and on-demand applications (e.g. [systemd](http://0pointer.de/blog/projects/socket-activation.html)). diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 455f0bb..cbc05a1 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -163,6 +163,7 @@ nav: - 'Ignore Files': 'features/ignore-files.md' - 'Health endpoint': 'features/health-endpoint.md' - 'Virtual Hosting': 'features/virtual-hosting.md' + - 'Multiple Index Files': 'features/multiple-index-files.md' - 'WebAssembly': 'features/webassembly.md' - 'Platforms & Architectures': 'platforms-architectures.md' - 'Migrating from v1 to v2': 'migration.md' diff --git a/src/handler.rs b/src/handler.rs index b07ed4e..fb548c5 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -70,6 +70,8 @@ pub struct RequestHandlerOpts { #[cfg(feature = "basic-auth")] #[cfg_attr(docsrs, doc(cfg(feature = "basic-auth")))] pub basic_auth: String, + /// Index files feature. + pub index_files: Vec, /// Log remote address feature. pub log_remote_address: bool, /// Redirect trailing slash feature. @@ -114,6 +116,7 @@ impl RequestHandler { let compression_static = self.opts.compression_static; let ignore_hidden_files = self.opts.ignore_hidden_files; let health = self.opts.health; + let index_files: Vec<&str> = self.opts.index_files.iter().map(|s| s.as_str()).collect(); let mut cors_headers: Option = None; @@ -359,6 +362,7 @@ impl RequestHandler { } let uri_path = &uri_path; + let index_files = index_files.as_ref(); // Static files match static_files::handle(&HandleOpts { @@ -376,6 +380,7 @@ impl RequestHandler { redirect_trailing_slash, compression_static, ignore_hidden_files, + index_files, }) .await { diff --git a/src/server.rs b/src/server.rs index f4632f3..4cae50f 100644 --- a/src/server.rs +++ b/src/server.rs @@ -252,6 +252,17 @@ impl Server { let grace_period = general.grace_period; server_info!("grace period before graceful shutdown: {}s", grace_period); + // Index files option + let index_files = general + .index_files + .split(',') + .map(|s| s.trim().to_owned()) + .collect::>(); + if index_files.is_empty() { + bail!("index files list is empty, provide at least one index file") + } + server_info!("index files: {}", general.index_files); + // Health endpoint option let health = general.health; server_info!("health endpoint: enabled={}", health); @@ -280,6 +291,7 @@ impl Server { log_remote_address, redirect_trailing_slash, ignore_hidden_files, + index_files, health, advanced_opts, }), @@ -419,6 +431,7 @@ impl Server { bail!("https redirect allowed hosts is empty, provide at least one host or IP") } + // Redirect options let redirect_opts = Arc::new(https_redirect::RedirectOpts { https_hostname: general.https_redirect_host, https_port: general.port, diff --git a/src/settings/cli.rs b/src/settings/cli.rs index 470f58b..c1320d3 100644 --- a/src/settings/cli.rs +++ b/src/settings/cli.rs @@ -226,6 +226,11 @@ pub struct General { /// List of host names or IPs allowed to redirect from. HTTP requests must contain the HTTP 'Host' header and match against this list. It depends on "https_redirect" to be enabled. pub https_redirect_from_hosts: String, + #[arg(long, default_value = "index.html", env = "SERVER_INDEX_FILES")] + /// List of files that will be used as an index for requests ending with the slash character (‘/’). + /// Files are checked in the specified order. + pub index_files: String, + #[cfg(feature = "compression")] #[cfg_attr(docsrs, doc(cfg(feature = "compression")))] #[arg( diff --git a/src/settings/file.rs b/src/settings/file.rs index cb2dd4e..69bc865 100644 --- a/src/settings/file.rs +++ b/src/settings/file.rs @@ -187,6 +187,9 @@ pub struct General { /// Cors expose headers feature. pub cors_expose_headers: Option, + /// List of files to be used as an index for requests ending with the slash character (‘/’). + pub index_files: Option, + /// Directory listing feature. #[cfg(feature = "directory-listing")] #[cfg_attr(docsrs, doc(cfg(feature = "directory-listing")))] diff --git a/src/settings/mod.rs b/src/settings/mod.rs index 39023b2..4de7f7d 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -145,6 +145,7 @@ impl Settings { let mut log_remote_address = opts.log_remote_address; let mut redirect_trailing_slash = opts.redirect_trailing_slash; let mut ignore_hidden_files = opts.ignore_hidden_files; + let mut index_files = opts.index_files; let mut health = opts.health; // Windows-only options @@ -284,6 +285,9 @@ impl Settings { if let Some(v) = general.health { health = v } + if let Some(v) = general.index_files { + index_files = v + } // Windows-only options #[cfg(windows)] @@ -508,6 +512,7 @@ impl Settings { log_remote_address, redirect_trailing_slash, ignore_hidden_files, + index_files, health, // Windows-only options and commands diff --git a/src/static_files.rs b/src/static_files.rs index 12ee3f4..1875ee7 100644 --- a/src/static_files.rs +++ b/src/static_files.rs @@ -39,6 +39,8 @@ use crate::{ directory_listing::{DirListFmt, DirListOpts}, }; +const DEFAULT_INDEX_FILES: &[&str; 1] = &["index.html"]; + /// Defines all options needed by the static-files handler. pub struct HandleOpts<'a> { /// Request method. @@ -49,6 +51,8 @@ pub struct HandleOpts<'a> { pub base_path: &'a PathBuf, /// Request base path. pub uri_path: &'a str, + /// Index files. + pub index_files: &'a [&'a str], /// Request URI query. pub uri_query: Option<&'a str>, /// Directory listing feature. @@ -91,7 +95,13 @@ pub async fn handle<'a>(opts: &HandleOpts<'a>) -> Result<(Response, bool), metadata, is_dir, precompressed_variant, - } = composed_file_metadata(&mut file_path, headers_opt, compression_static_opt).await?; + } = composed_file_metadata( + &mut file_path, + headers_opt, + compression_static_opt, + opts.index_files, + ) + .await?; // Check for a hidden file/directory (dotfile) and ignore it if feature enabled if opts.ignore_hidden_files && file_path.is_hidden() { @@ -215,48 +225,63 @@ async fn composed_file_metadata<'a>( mut file_path: &'a mut PathBuf, _headers: &'a HeaderMap, _compression_static: bool, + mut index_files: &'a [&'a str], ) -> Result, StatusCode> { tracing::trace!("getting metadata for file {}", file_path.display()); match file_metadata(file_path) { Ok((mut metadata, is_dir)) => { if is_dir { - // Append a HTML index page by default if it's a directory path (`autoindex`) - tracing::debug!("dir: appending an index.html to the directory path"); - file_path.push("index.html"); - - // Pre-compressed variant check for the autoindex - #[cfg(feature = "compression")] - if _compression_static { - if let Some(p) = - compression_static::precompressed_variant(file_path, _headers).await - { - return Ok(FileMetadata { - file_path, - metadata: p.metadata, - is_dir: false, - precompressed_variant: Some((p.file_path, p.extension)), - }); - } + // Try every index file variant in order + if index_files.is_empty() { + index_files = DEFAULT_INDEX_FILES; } + let mut index_found = false; + for index in index_files { + // Append a HTML index page by default if it's a directory path (`autoindex`) + tracing::debug!("dir: appending {} to the directory path", index); + file_path.push(index); + + // Pre-compressed variant check for the autoindex + #[cfg(feature = "compression")] + if _compression_static { + if let Some(p) = + compression_static::precompressed_variant(file_path, _headers).await + { + return Ok(FileMetadata { + file_path, + metadata: p.metadata, + is_dir: false, + precompressed_variant: Some((p.file_path, p.extension)), + }); + } + } - // Otherwise, just fallback to finding the index.html - // and overwrite the current `meta` - // Also noting that it's still a directory request - if let Ok(meta_res) = file_metadata(file_path) { - (metadata, _) = meta_res - } else { - // We remove the appended index.html - file_path.pop(); - let new_meta: Option; - (file_path, new_meta) = suffix_file_html_metadata(file_path); - if let Some(new_meta) = new_meta { - metadata = new_meta; + // Otherwise, just fallback to finding the index.html + // and overwrite the current `meta` + // Also noting that it's still a directory request + if let Ok(meta_res) = file_metadata(file_path) { + (metadata, _) = meta_res; + index_found = true; + break; } else { - // We append the index.html to preserve previous behavior - file_path.push("index.html"); + // We remove only the appended index file + file_path.pop(); + let new_meta: Option; + (file_path, new_meta) = suffix_file_html_metadata(file_path); + if let Some(new_meta) = new_meta { + metadata = new_meta; + index_found = true; + break; + } } } + + // In case no index was found then we append the last index + // of the list to preserve the previous behavior + if !index_found && !index_files.is_empty() { + file_path.push(index_files.last().unwrap()); + } } else { // Fallback pre-compressed variant check for the specific file #[cfg(feature = "compression")] diff --git a/tests/compression_static.rs b/tests/compression_static.rs index 35f291b..f614c6c 100644 --- a/tests/compression_static.rs +++ b/tests/compression_static.rs @@ -48,6 +48,7 @@ mod tests { #[cfg(feature = "compression")] compression_static: true, ignore_hidden_files: false, + index_files: &[], }) .await .expect("unexpected error response on `handle` function"); @@ -106,6 +107,7 @@ mod tests { #[cfg(feature = "compression")] compression_static: true, ignore_hidden_files: false, + index_files: &[], }) .await .expect("unexpected error response on `handle` function"); @@ -158,6 +160,7 @@ mod tests { redirect_trailing_slash: true, compression_static: true, ignore_hidden_files: false, + index_files: &[], }) .await .expect("unexpected error response on `handle` function"); diff --git a/tests/dir_listing.rs b/tests/dir_listing.rs index b1b2b27..851b089 100644 --- a/tests/dir_listing.rs +++ b/tests/dir_listing.rs @@ -49,6 +49,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -79,6 +80,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -119,6 +121,7 @@ mod tests { redirect_trailing_slash: false, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -159,6 +162,7 @@ mod tests { redirect_trailing_slash: false, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -189,6 +193,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -240,6 +245,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: true, + index_files: &[], }) .await { @@ -254,7 +260,7 @@ mod tests { if method == Method::GET { let entries: Vec = serde_json::from_str(body_str).unwrap(); - assert_eq!(entries.len(), 2); + assert_eq!(entries.len(), 3); let first_entry = entries.first().unwrap(); assert_eq!(first_entry.name, "spécial directöry"); @@ -263,10 +269,10 @@ mod tests { assert!(first_entry.size.is_none()); let last_entry = entries.last().unwrap(); - assert_eq!(last_entry.name, "index.html.gz"); + assert_eq!(last_entry.name, "index.htm"); assert_eq!(last_entry.typed, "file"); assert!(!last_entry.mtime.is_empty()); - assert!(last_entry.size.unwrap() > 300); + assert!(last_entry.size.unwrap() >= 36); } else { assert!(body_str.is_empty()); } @@ -309,6 +315,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -351,6 +358,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: true, + index_files: &[], }) .await { diff --git a/tests/fixtures/public/index.htm b/tests/fixtures/public/index.htm new file mode 100644 index 0000000..ad3452f --- /dev/null +++ b/tests/fixtures/public/index.htm @@ -0,0 +1 @@ +

this is a custom index file

diff --git a/tests/static_files.rs b/tests/static_files.rs index 6007ab0..0c55a54 100644 --- a/tests/static_files.rs +++ b/tests/static_files.rs @@ -39,6 +39,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await .expect("unexpected error response on `handle` function"); @@ -80,6 +81,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await .expect("unexpected error response on `handle` function"); @@ -122,6 +124,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -152,6 +155,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await .expect("unexpected error response on `handle` function"); @@ -183,6 +187,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -213,6 +218,7 @@ mod tests { redirect_trailing_slash: false, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -248,6 +254,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -298,6 +305,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -330,6 +338,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -365,6 +374,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -400,6 +410,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -438,6 +449,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -474,6 +486,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -508,6 +521,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -541,6 +555,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -588,6 +603,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -649,6 +665,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -712,6 +729,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -759,6 +777,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -806,6 +825,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -854,6 +874,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -894,6 +915,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -944,6 +966,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -991,6 +1014,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -1041,6 +1065,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -1089,6 +1114,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -1132,6 +1158,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -1186,6 +1213,7 @@ mod tests { redirect_trailing_slash: true, compression_static: false, ignore_hidden_files: false, + index_files: &[], }) .await { @@ -1232,6 +1260,7 @@ mod tests { redirect_trailing_slash: true, compression_static: true, ignore_hidden_files: true, + index_files: &[], }) .await { @@ -1244,4 +1273,48 @@ mod tests { } } } + + #[tokio::test] + async fn handle_multiple_index_files() { + let root_dir = PathBuf::from("tests/fixtures/public/"); + let headers = HeaderMap::new(); + + let buf = fs::read(root_dir.join("index.htm")) + .expect("unexpected error during index.htm reading"); + let buf = Bytes::from(buf); + + for method in [Method::HEAD, Method::GET] { + match static_files::handle(&HandleOpts { + method: &method, + headers: &headers, + base_path: &root_dir, + uri_path: "/", + uri_query: None, + #[cfg(feature = "directory-listing")] + dir_listing: false, + #[cfg(feature = "directory-listing")] + dir_listing_order: 6, + #[cfg(feature = "directory-listing")] + dir_listing_format: &DirListFmt::Html, + redirect_trailing_slash: true, + compression_static: true, + ignore_hidden_files: true, + index_files: &["index.html", "index.htm"], + }) + .await + { + Ok((mut res, _)) => { + assert_eq!(res.status(), 200); + assert_eq!(res.headers()["content-length"], format!("{}", buf.len())); + let body = hyper::body::to_bytes(res.body_mut()) + .await + .expect("unexpected bytes error during `body` conversion"); + assert_eq!(body, &buf); + } + Err(_) => { + panic!("expected a normal response rather than a status error") + } + } + } + } } diff --git a/tests/toml/config.toml b/tests/toml/config.toml index 3d3b3ff..3bbf5a6 100644 --- a/tests/toml/config.toml +++ b/tests/toml/config.toml @@ -65,6 +65,9 @@ redirect-trailing-slash = true #### Check for existing pre-compressed files compression-static = false +#### List of index files +index-files = "index.html, index.htm" + ### Windows Only #### Run the web server as a Windows Service -- libgit2 1.7.2