Add cache-busting and server headers with a wrapper.

In order to support custom headers for various response types,
  this commit adds a wrapper type, ResponseWrapper, which can service
  all types of response in `bin`.

For paste objects, the preferred `Last-Modified` is used, so that caches
  can compare their exact timings with the HEAD response when
  revalidating.

For static objects, an `ETag` is used instead, based on the Cargo version
  and git hash of the codebase at compilation time; a `build.rs` is used
  for this.
This commit is contained in:
Leonora Tindall
2022-02-04 13:47:30 -06:00
committed by Gunwant Jain
parent 55ed495b83
commit 2ab7ddb9c8
12 changed files with 292 additions and 153 deletions

View File

@@ -1,26 +1,62 @@
use rocket::response::Redirect;
use rocket_dyn_templates::Template;
use std::fs;
use std::collections::HashMap;
use std::io::ErrorKind::InvalidData;
use std::io::ErrorKind::{InvalidData, NotFound};
use std::path::Path;
use crate::get_upload_dir;
use crate::models::maybe_redirect::MaybeRedirect;
use crate::models::paste_id::PasteId;
use crate::models::pretty::get_pretty_body;
use crate::models::pretty_syntax::PasteIdSyntax;
use crate::models::response_wrapper::ResponseWrapper;
#[get("/p/<id>", rank = 2)]
pub async fn pretty_retrieve(id: PasteId<'_>) -> Option<MaybeRedirect> {
let filepath = Path::new(&get_upload_dir()).join(format!("{id}", id = id));
pub async fn pretty_retrieve(id: PasteId<'_>) -> ResponseWrapper<Template> {
pretter_retrieve_inner(&id.to_string(), "txt").await
}
let contents = match get_pretty_body(&filepath, &String::from("txt")) {
#[get("/p/<id_ext>", rank = 1)]
pub async fn pretty_retrieve_ext(
id_ext: PasteIdSyntax<'_>,
) -> ResponseWrapper<Template> {
let id = id_ext.get_fname();
let ext = id_ext.get_ext();
pretter_retrieve_inner(id, ext).await
}
pub async fn pretter_retrieve_inner(
id: &str,
ext: &str,
) -> ResponseWrapper<Template> {
let filepath = Path::new(&get_upload_dir()).join(id.to_string());
let modified_date =
match fs::metadata(&filepath).and_then(|m| m.modified()) {
Ok(v) => v,
Err(e) if e.kind() == NotFound => {
return ResponseWrapper::not_found(id);
}
Err(e) => {
return ResponseWrapper::server_error(e.to_string());
}
};
let contents = match get_pretty_body(&filepath, ext) {
Ok(v) => v,
Err(e) if e.kind() == InvalidData => {
return Some(Redirect::to(format!("/{}", id)).into());
return ResponseWrapper::redirect(Redirect::permanent(format!(
"/{}",
id
)));
}
_ => {
return None;
Err(e) if e.kind() == NotFound => {
return ResponseWrapper::not_found(id)
}
Err(e) => {
return ResponseWrapper::server_error(e.to_string());
}
};
@@ -30,7 +66,7 @@ pub async fn pretty_retrieve(id: PasteId<'_>) -> Option<MaybeRedirect> {
let rendered = Template::render("pretty.html", &map);
match tree_magic::match_filepath("text/plain", &filepath) {
true => Some(rendered.into()),
false => None,
true => ResponseWrapper::paste_response(rendered, modified_date),
false => ResponseWrapper::server_error("media type unacceptable"),
}
}