Skip to content

Commit

Permalink
Merge branch 'master' into directory-listing-init
Browse files Browse the repository at this point in the history
  • Loading branch information
palant committed Apr 28, 2024
2 parents 0ab04b1 + f311e94 commit b517365
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 77 deletions.
10 changes: 6 additions & 4 deletions src/compression_static.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use std::{

use crate::{
compression, handler::RequestHandlerOpts, headers_ext::ContentCoding,
static_files::file_metadata,
static_files::file_metadata, Error,
};

/// It defines the pre-compressed file variant metadata of a particular file path.
Expand All @@ -39,17 +39,19 @@ pub fn init(enabled: bool, handler_opts: &mut RequestHandlerOpts) {
pub(crate) fn post_process(
opts: &RequestHandlerOpts,
_req: &Request<Body>,
resp: &mut Response<Body>,
) {
mut resp: Response<Body>,
) -> Result<Response<Body>, Error> {
if !opts.compression_static {
return;
return Ok(resp);
}

// Compression content encoding varies so use a `Vary` header
resp.headers_mut().append(
hyper::header::VARY,
HeaderValue::from_name(hyper::header::ACCEPT_ENCODING),
);

Ok(resp)
}

/// Search for the pre-compressed variant of the given file path.
Expand Down
9 changes: 5 additions & 4 deletions src/control_headers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

use hyper::{Body, Request, Response};

use crate::handler::RequestHandlerOpts;
use crate::{handler::RequestHandlerOpts, Error};

// Cache-Control `max-age` variants
const MAX_AGE_ONE_HOUR: u64 = 60 * 60;
Expand All @@ -33,11 +33,12 @@ pub(crate) fn init(enabled: bool, handler_opts: &mut RequestHandlerOpts) {
pub(crate) fn post_process(
opts: &RequestHandlerOpts,
req: &Request<Body>,
resp: &mut Response<Body>,
) {
mut resp: Response<Body>,
) -> Result<Response<Body>, Error> {
if opts.cache_control_headers {
append_headers(req.uri().path(), resp);
append_headers(req.uri().path(), &mut resp);
}
Ok(resp)
}

/// It appends a `Cache-Control` header to a response if that one is part of a set of file types.
Expand Down
29 changes: 16 additions & 13 deletions src/cors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,8 +421,8 @@ pub(crate) fn pre_process(
pub(crate) fn post_process(
opts: &RequestHandlerOpts,
req: &Request<Body>,
resp: &mut Response<Body>,
) {
mut resp: Response<Body>,
) -> Result<Response<Body>, Error> {
if let Some(cors) = opts.cors.as_ref() {
if let Ok((headers, _)) = cors.check_request(req.method(), req.headers()) {
if !headers.is_empty() {
Expand All @@ -433,6 +433,7 @@ pub(crate) fn post_process(
}
}
}
Ok(resp)
}

#[cfg(test)]
Expand Down Expand Up @@ -478,7 +479,7 @@ mod tests {
}

#[test]
fn test_cors_disabled() {
fn test_cors_disabled() -> Result<(), Error> {
let opts = RequestHandlerOpts {
cors: None,
..Default::default()
Expand All @@ -487,13 +488,14 @@ mod tests {

assert!(pre_process(&opts, &req).is_none());

let mut resp = make_response();
post_process(&opts, &req, &mut resp);
let resp = post_process(&opts, &req, make_response())?;
assert_eq!(get_allowed_origin(resp), None);

Ok(())
}

#[test]
fn test_non_cors_request() {
fn test_non_cors_request() -> Result<(), Error> {
let opts = RequestHandlerOpts {
cors: make_cors_config(),
..Default::default()
Expand All @@ -502,9 +504,10 @@ mod tests {

assert!(pre_process(&opts, &req).is_none());

let mut resp = make_response();
post_process(&opts, &req, &mut resp);
let resp = post_process(&opts, &req, make_response())?;
assert_eq!(get_allowed_origin(resp), None);

Ok(())
}

#[test]
Expand Down Expand Up @@ -539,7 +542,7 @@ mod tests {
}

#[test]
fn test_allowed_request() {
fn test_allowed_request() -> Result<(), Error> {
let opts = RequestHandlerOpts {
cors: make_cors_config(),
..Default::default()
Expand All @@ -548,8 +551,7 @@ mod tests {
let req = make_request("GET", "https://example.com");
assert!(pre_process(&opts, &req).is_none());

let mut resp = make_response();
post_process(&opts, &req, &mut resp);
let resp = post_process(&opts, &req, make_response())?;
assert_eq!(get_allowed_origin(resp), Some("https://example.com".into()));

let mut req = make_request("GET", "https://example.com");
Expand All @@ -561,8 +563,9 @@ mod tests {
);
assert!(pre_process(&opts, &req).is_none());

let mut resp = make_response();
post_process(&opts, &req, &mut resp);
let resp = post_process(&opts, &req, make_response())?;
assert_eq!(get_allowed_origin(resp), Some("https://example.com".into()));

Ok(())
}
}
9 changes: 5 additions & 4 deletions src/custom_headers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,24 @@
use hyper::{Body, Request, Response};
use std::{ffi::OsStr, path::PathBuf};

use crate::{handler::RequestHandlerOpts, settings::Headers};
use crate::{handler::RequestHandlerOpts, settings::Headers, Error};

/// Appends custom HTTP headers to a response if necessary
pub(crate) fn post_process(
opts: &RequestHandlerOpts,
req: &Request<Body>,
resp: &mut Response<Body>,
mut resp: Response<Body>,
file_path: Option<&PathBuf>,
) {
) -> Result<Response<Body>, Error> {
if let Some(advanced) = &opts.advanced_opts {
append_headers(
req.uri().path(),
advanced.headers.as_deref(),
resp,
&mut resp,
file_path,
)
}
Ok(resp)
}

/// Append custom HTTP headers to current response.
Expand Down
164 changes: 163 additions & 1 deletion src/fallback_page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,40 @@
//!

use headers::{AcceptRanges, ContentLength, ContentType, HeaderMapExt};
use hyper::{Body, Response, StatusCode};
use hyper::{Body, Request, Response, StatusCode};
use mime_guess::mime;
use std::path::Path;

use crate::{handler::RequestHandlerOpts, helpers, http_ext::MethodExt, Error};

/// Initializes fallback page processing
pub(crate) fn init(path: &Path, handler_opts: &mut RequestHandlerOpts) {
handler_opts.page_fallback = helpers::read_bytes_default(path);

server_info!(
"fallback page: enabled={}, value=\"{}\"",
!handler_opts.page_fallback.is_empty(),
path.to_string_lossy()
);
}

/// Replace 404 Not Found by the configured fallback page
pub(crate) fn post_process(
opts: &RequestHandlerOpts,
req: &Request<Body>,
resp: Response<Body>,
) -> Result<Response<Body>, Error> {
Ok(
if req.method().is_get()
&& resp.status() == StatusCode::NOT_FOUND
&& !opts.page_fallback.is_empty()
{
fallback_response(&opts.page_fallback)
} else {
resp
},
)
}

/// Checks if a fallback response can be generated, i.e. if it is a `GET` request
/// that would result in a `404` error and a fallback page is configured.
Expand All @@ -27,3 +59,133 @@ pub fn fallback_response(page_fallback: &[u8]) -> Response<Body> {

resp
}

#[cfg(test)]
mod tests {
use super::post_process;
use crate::{error_page, handler::RequestHandlerOpts, Error};
use hyper::{Body, Method, Request, Response, StatusCode, Uri};
use std::path::PathBuf;

fn make_request(method: &str) -> Request<Body> {
Request::builder()
.method(method)
.uri("/")
.body(Body::empty())
.unwrap()
}

fn make_response(status: &StatusCode) -> Response<Body> {
error_page::error_response(
&Uri::try_from("/").unwrap(),
&Method::GET,
status,
&PathBuf::new(),
&PathBuf::new(),
)
.unwrap()
}

#[test]
fn test_success_code() -> Result<(), Error> {
let opts = RequestHandlerOpts {
page_fallback: vec![1, 2, 3],
..Default::default()
};
let req = make_request("GET");
let resp = make_response(&StatusCode::OK);

let resp = post_process(&opts, &req, resp)?;
assert_eq!(resp.status(), StatusCode::OK);
assert_ne!(
resp.headers()
.get("Content-Length")
.map(|v| v.to_str().unwrap())
.unwrap_or("3"),
"3"
);

Ok(())
}

#[test]
fn test_wrong_error() -> Result<(), Error> {
let opts = RequestHandlerOpts {
page_fallback: vec![1, 2, 3],
..Default::default()
};
let req = make_request("GET");
let resp = make_response(&StatusCode::INTERNAL_SERVER_ERROR);

let resp = post_process(&opts, &req, resp)?;
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
assert_ne!(
resp.headers()
.get("Content-Length")
.map(|v| v.to_str().unwrap())
.unwrap_or("3"),
"3"
);

Ok(())
}

#[test]
fn test_wrong_method() -> Result<(), Error> {
let opts = RequestHandlerOpts {
page_fallback: vec![1, 2, 3],
..Default::default()
};
let req = make_request("POST");
let resp = make_response(&StatusCode::NOT_FOUND);

let resp = post_process(&opts, &req, resp)?;
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
assert_ne!(
resp.headers()
.get("Content-Length")
.map(|v| v.to_str().unwrap())
.unwrap_or("3"),
"3"
);

Ok(())
}

#[test]
fn test_unconfigured() -> Result<(), Error> {
let opts = RequestHandlerOpts {
page_fallback: Vec::new(),
..Default::default()
};
let req = make_request("GET");
let resp = make_response(&StatusCode::NOT_FOUND);

let resp = post_process(&opts, &req, resp)?;
assert_eq!(resp.status(), StatusCode::NOT_FOUND);

Ok(())
}

#[test]
fn test_fallback() -> Result<(), Error> {
let opts = RequestHandlerOpts {
page_fallback: vec![1, 2, 3],
..Default::default()
};
let req = make_request("GET");
let resp = make_response(&StatusCode::NOT_FOUND);

let resp = post_process(&opts, &req, resp)?;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.headers()
.get("Content-Length")
.map(|v| v.to_str().unwrap())
.unwrap_or("3"),
"3"
);

Ok(())
}
}
Loading

0 comments on commit b517365

Please sign in to comment.