Skip to content

Commit

Permalink
refactor: decrease allocations during 404/50x error page responses
Browse files Browse the repository at this point in the history
  • Loading branch information
joseluisq committed Jul 12, 2021
1 parent 18de7fd commit 157ade1
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 62 deletions.
40 changes: 15 additions & 25 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Expand Up @@ -40,7 +40,6 @@ bytes = "1.0"
percent-encoding = "2.1"
structopt = { version = "0.3", default-features = false }
num_cpus = { version = "1.13" }
once_cell = "1.7"
pin-project = "1.0"
tokio-rustls = { version = "0.22" }
humansize = "1.1"
Expand Down
47 changes: 20 additions & 27 deletions src/error_page.rs
@@ -1,15 +1,16 @@
use headers::{AcceptRanges, ContentLength, ContentType, HeaderMapExt, HeaderValue};
use http::header::CONTENT_TYPE;
use hyper::{Body, Method, Response, StatusCode};
use once_cell::sync::OnceCell;

use crate::Result;

pub static PAGE_404: OnceCell<String> = OnceCell::new();
pub static PAGE_50X: OnceCell<String> = OnceCell::new();

/// It returns a HTTP error response which also handles available `404` or `50x` HTML content.
pub fn error_response(method: &Method, status_code: &StatusCode) -> Result<Response<Body>> {
pub fn error_response(
method: &Method,
status_code: &StatusCode,
page404: &str,
page50x: &str,
) -> Result<Response<Body>> {
tracing::warn!(method = ?method, status = status_code.as_u16(), error = ?status_code.to_owned());

// Check for 4xx/50x status codes and handle their corresponding HTML content
Expand All @@ -36,15 +37,7 @@ pub fn error_response(method: &Method, status_code: &StatusCode) -> Result<Respo
| &StatusCode::EXPECTATION_FAILED => {
// Extra check for 404 status code and its HTML content
if status_code == &StatusCode::NOT_FOUND {
error_page_content = match PAGE_404.get() {
Some(s) => s.to_owned(),
None => {
tracing::error!(
"404 error page content is not accessible or `PAGE_404` uninitialized"
);
String::new()
}
};
error_page_content = page404.to_owned();
}
status_code
}
Expand All @@ -59,26 +52,26 @@ pub fn error_response(method: &Method, status_code: &StatusCode) -> Result<Respo
| &StatusCode::INSUFFICIENT_STORAGE
| &StatusCode::LOOP_DETECTED => {
// HTML content check for status codes 50x
error_page_content = match PAGE_50X.get() {
Some(s) => s.to_owned(),
None => {
tracing::error!(
"50x error page content is not accessible or `PAGE_50X` uninitialized"
);
String::new()
}
};
error_page_content = page50x.to_owned();
status_code
}
// other status codes
_ => status_code,
};

if error_page_content.is_empty() {
error_page_content = format!(
"<html><head><title>{}</title></head><body><center><h1>{}</h1></center></body></html>",
status_code, status_code
);
error_page_content = [
"<html><head><title>",
status_code.as_str(),
" ",
status_code.canonical_reason().unwrap_or_default(),
"</title></head><body><center><h1>",
status_code.as_str(),
" ",
status_code.canonical_reason().unwrap_or_default(),
"</h1></center></body></html>",
]
.concat();
}

let mut body = Body::empty();
Expand Down
18 changes: 16 additions & 2 deletions src/handler.rs
Expand Up @@ -12,6 +12,8 @@ pub struct RequestHandlerOpts {
pub dir_listing: bool,
pub cors: Option<Arc<cors::Configured>>,
pub security_headers: bool,
pub page404: Arc<str>,
pub page50x: Arc<str>,
}

/// It defines the main request handler used by the Hyper service request.
Expand Down Expand Up @@ -42,7 +44,12 @@ impl RequestHandler {
}
Err(e) => {
tracing::debug!("cors error kind: {:?}", e);
return error_page::error_response(method, &StatusCode::FORBIDDEN);
return error_page::error_response(
method,
&StatusCode::FORBIDDEN,
self.opts.page404.as_ref(),
self.opts.page50x.as_ref(),
);
}
};
}
Expand All @@ -59,6 +66,8 @@ impl RequestHandler {
return error_page::error_response(
method,
&StatusCode::INTERNAL_SERVER_ERROR,
self.opts.page404.as_ref(),
self.opts.page50x.as_ref(),
);
}
};
Expand All @@ -75,7 +84,12 @@ impl RequestHandler {

Ok(resp)
}
Err(status) => error_page::error_response(method, &status),
Err(status) => error_page::error_response(
method,
&status,
self.opts.page404.as_ref(),
self.opts.page50x.as_ref(),
),
}
}
}
Expand Down
12 changes: 5 additions & 7 deletions src/server.rs
Expand Up @@ -8,7 +8,7 @@ use structopt::StructOpt;
use crate::handler::{RequestHandler, RequestHandlerOpts};
use crate::tls::{TlsAcceptor, TlsConfigBuilder};
use crate::{config::Config, service::RouterService, Result};
use crate::{cors, error_page, helpers, logger, signals};
use crate::{cors, helpers, logger, signals};

/// Define a multi-thread HTTP or HTTP/2 web server.
pub struct Server {
Expand Down Expand Up @@ -81,12 +81,8 @@ impl Server {
let root_dir = Arc::new(helpers::get_valid_dirpath(&opts.root)?);

// Custom error pages content
error_page::PAGE_404
.set(helpers::read_file_content(opts.page404.as_ref()))
.expect("page 404 is not initialized");
error_page::PAGE_50X
.set(helpers::read_file_content(opts.page50x.as_ref()))
.expect("page 50x is not initialized");
let page404 = Arc::from(helpers::read_file_content(opts.page404.as_ref()).as_str());
let page50x = Arc::from(helpers::read_file_content(opts.page50x.as_ref()).as_str());

// Number of worker threads option
let threads = self.threads;
Expand Down Expand Up @@ -115,6 +111,8 @@ impl Server {
dir_listing,
cors,
security_headers,
page404,
page50x,
},
});

Expand Down

0 comments on commit 157ade1

Please sign in to comment.