You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-08-06 06:02:40 +03:00
Support ETag header and HEAD requests in static files
This commit is contained in:
@@ -24,11 +24,11 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
body::{boxed, Full},
|
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
|
TypedHeader,
|
||||||
};
|
};
|
||||||
use headers::{ContentLength, ContentType, HeaderMapExt};
|
use headers::{ContentLength, ContentType, ETag, HeaderMapExt, IfNoneMatch};
|
||||||
use http::{Request, StatusCode};
|
use http::{Method, Request, StatusCode};
|
||||||
use rust_embed::RustEmbed;
|
use rust_embed::RustEmbed;
|
||||||
use tower::Service;
|
use tower::Service;
|
||||||
|
|
||||||
@@ -40,15 +40,49 @@ use tower::Service;
|
|||||||
pub struct Assets;
|
pub struct Assets;
|
||||||
|
|
||||||
impl Assets {
|
impl Assets {
|
||||||
fn get_response(path: &str) -> Option<Response> {
|
fn get_response(
|
||||||
|
is_head: bool,
|
||||||
|
path: &str,
|
||||||
|
if_none_match: Option<IfNoneMatch>,
|
||||||
|
) -> Option<Response> {
|
||||||
let asset = Self::get(path)?;
|
let asset = Self::get(path)?;
|
||||||
|
|
||||||
|
let etag: String = asset
|
||||||
|
.metadata
|
||||||
|
.sha256_hash()
|
||||||
|
.iter()
|
||||||
|
.map(|x| format!("{:02x}", x))
|
||||||
|
.collect();
|
||||||
|
let etag: ETag = format!("\"{}\"", etag).parse().unwrap();
|
||||||
|
|
||||||
|
if let Some(if_none_match) = if_none_match {
|
||||||
|
if if_none_match.precondition_passes(&etag) {
|
||||||
|
return Some(StatusCode::NOT_MODIFIED.into_response());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let len = asset.data.len().try_into().unwrap();
|
let len = asset.data.len().try_into().unwrap();
|
||||||
let mime = mime_guess::from_path(path).first_or_octet_stream();
|
let mime = mime_guess::from_path(path).first_or_octet_stream();
|
||||||
|
|
||||||
let mut res = Response::new(boxed(Full::from(asset.data)));
|
let res = if is_head {
|
||||||
res.headers_mut().typed_insert(ContentType::from(mime));
|
(
|
||||||
res.headers_mut().typed_insert(ContentLength(len));
|
StatusCode::OK,
|
||||||
|
TypedHeader(ContentType::from(mime)),
|
||||||
|
TypedHeader(ContentLength(len)),
|
||||||
|
TypedHeader(etag),
|
||||||
|
)
|
||||||
|
.into_response()
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
StatusCode::OK,
|
||||||
|
TypedHeader(ContentType::from(mime)),
|
||||||
|
TypedHeader(ContentLength(len)),
|
||||||
|
TypedHeader(etag),
|
||||||
|
asset.data,
|
||||||
|
)
|
||||||
|
.into_response()
|
||||||
|
};
|
||||||
|
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,11 +101,16 @@ impl<B> Service<Request<B>> for Assets {
|
|||||||
|
|
||||||
fn call(&mut self, req: Request<B>) -> Self::Future {
|
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||||
let path = req.uri().path().trim_start_matches('/');
|
let path = req.uri().path().trim_start_matches('/');
|
||||||
// TODO: support HEAD requests
|
let if_none_match = req.headers().typed_get();
|
||||||
// TODO: support ETag
|
let is_head = match *req.method() {
|
||||||
|
Method::GET => false,
|
||||||
|
Method::HEAD => true,
|
||||||
|
_ => return ready(Ok(StatusCode::METHOD_NOT_ALLOWED.into_response())),
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: support range requests
|
// TODO: support range requests
|
||||||
let response =
|
let response = Self::get_response(is_head, path, if_none_match)
|
||||||
Self::get_response(path).unwrap_or_else(|| StatusCode::NOT_FOUND.into_response());
|
.unwrap_or_else(|| StatusCode::NOT_FOUND.into_response());
|
||||||
ready(Ok(response))
|
ready(Ok(response))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user