Thumbnail and audio endpoints no longer encode payloads

This commit is contained in:
Antoine Gersant 2021-11-28 20:13:54 -08:00
parent f27bc4ccfc
commit 39c8cf7595
3 changed files with 70 additions and 9 deletions
src/service

View file

@ -2,17 +2,17 @@ use actix_files::NamedFile;
use actix_web::{
client::HttpError,
delete,
dev::{MessageBody, Payload, Service, ServiceRequest, ServiceResponse},
dev::{BodyEncoding, MessageBody, Payload, Service, ServiceRequest, ServiceResponse},
error::{BlockingError, ErrorForbidden, ErrorInternalServerError, ErrorUnauthorized},
get,
http::StatusCode,
http::{ContentEncoding, StatusCode},
post, put,
web::{self, Data, Json, JsonConfig, ServiceConfig},
FromRequest, HttpMessage, HttpRequest, HttpResponse, ResponseError,
FromRequest, HttpMessage, HttpRequest, HttpResponse, Responder, ResponseError,
};
use actix_web_httpauth::extractors::{basic::BasicAuth, bearer::BearerAuth};
use cookie::{self, *};
use futures_util::future::{err, ok};
use futures_util::future::{err, ok, ready, Ready};
use percent_encoding::percent_decode_str;
use std::future::Future;
use std::ops::Deref;
@ -378,6 +378,34 @@ fn add_auth_cookies<T>(
Ok(())
}
struct MediaFile {
named_file: NamedFile,
}
impl MediaFile {
fn new(named_file: NamedFile) -> Self {
Self {
named_file: named_file,
}
}
}
impl Responder for MediaFile {
type Error = actix_web::Error;
type Future = Ready<Result<HttpResponse, actix_web::Error>>;
fn respond_to(self, req: &HttpRequest) -> Self::Future {
let mut response = self.named_file.into_response(req);
if let Ok(r) = response.as_mut() {
// Intentionally turn off content encoding for media files because:
// 1. There is little value in compressing files that are already compressed (mp3, jpg, etc.)
// 2. The Content-Length header is incompatible with content encoding (other than identity), and can be valuable for clients
r.encoding(ContentEncoding::Identity);
}
return ready(response);
}
}
async fn block<F, I, E>(f: F) -> Result<I, APIError>
where
F: FnOnce() -> Result<I, E> + Send + 'static,
@ -681,7 +709,7 @@ async fn get_audio(
vfs_manager: Data<vfs::Manager>,
_auth: Auth,
path: web::Path<String>,
) -> Result<NamedFile, APIError> {
) -> Result<MediaFile, APIError> {
let audio_path = block(move || {
let vfs = vfs_manager.get_vfs()?;
let path = percent_decode_str(&(path.0)).decode_utf8_lossy();
@ -691,7 +719,7 @@ async fn get_audio(
.await?;
let named_file = NamedFile::open(&audio_path).map_err(|_| APIError::AudioFileIOError)?;
Ok(named_file)
Ok(MediaFile::new(named_file))
}
#[get("/thumbnail/{path:.*}")]
@ -701,7 +729,7 @@ async fn get_thumbnail(
_auth: Auth,
path: web::Path<String>,
options_input: web::Query<dto::ThumbnailOptions>,
) -> Result<NamedFile, APIError> {
) -> Result<MediaFile, APIError> {
let options = thumbnail::Options::from(options_input.0);
let thumbnail_path = block(move || {
@ -719,7 +747,7 @@ async fn get_thumbnail(
let named_file =
NamedFile::open(&thumbnail_path).map_err(|_| APIError::ThumbnailFileIOError)?;
Ok(named_file)
Ok(MediaFile::new(named_file))
}
#[get("/playlists")]

View file

@ -4,7 +4,7 @@ use crate::app::{config, ddns, settings, thumbnail, user, vfs};
use std::convert::From;
pub const API_MAJOR_VERSION: i32 = 6;
pub const API_MINOR_VERSION: i32 = 0;
pub const API_MINOR_VERSION: i32 = 1;
pub const COOKIE_SESSION: &str = "session";
pub const COOKIE_USERNAME: &str = "username";
pub const COOKIE_ADMIN: &str = "admin";

View file

@ -34,6 +34,39 @@ fn audio_golden_path() {
let response = service.fetch_bytes(&request);
assert_eq!(response.status(), StatusCode::OK);
assert_eq!(response.body().len(), 24_142);
assert_eq!(
response.headers().get(header::CONTENT_LENGTH).unwrap(),
"24142"
);
}
#[test]
fn audio_does_not_encode_content() {
let mut service = ServiceType::new(&test_name!());
service.complete_initial_setup();
service.login_admin();
service.index();
service.login();
let path: PathBuf = [TEST_MOUNT_NAME, "Khemmis", "Hunted", "02 - Candlelight.mp3"]
.iter()
.collect();
let mut request = protocol::audio(&path);
let headers = request.headers_mut();
headers.append(
header::ACCEPT_ENCODING,
HeaderValue::from_str("gzip, deflate, br").unwrap(),
);
let response = service.fetch_bytes(&request);
assert_eq!(response.status(), StatusCode::OK);
assert_eq!(response.body().len(), 24_142);
assert_eq!(response.headers().get(header::TRANSFER_ENCODING), None);
assert_eq!(
response.headers().get(header::CONTENT_LENGTH).unwrap(),
"24142"
);
}
#[test]