pict-rs/src/validate.rs

141 lines
4.6 KiB
Rust
Raw Normal View History

2021-10-21 01:13:39 +00:00
use crate::{
config::{AudioCodec, ImageFormat, VideoCodec},
2022-03-29 16:04:56 +00:00
either::Either,
error::{Error, UploadError},
ffmpeg::InputFormat,
magick::ValidInputType,
2021-10-21 01:13:39 +00:00
};
use actix_web::web::Bytes;
use tokio::io::AsyncRead;
2021-09-14 01:22:42 +00:00
use tracing::instrument;
struct UnvalidatedBytes {
bytes: Bytes,
written: usize,
}
impl UnvalidatedBytes {
fn new(bytes: Bytes) -> Self {
UnvalidatedBytes { bytes, written: 0 }
}
}
impl AsyncRead for UnvalidatedBytes {
fn poll_read(
mut self: std::pin::Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
buf: &mut tokio::io::ReadBuf<'_>,
) -> std::task::Poll<std::io::Result<()>> {
let bytes_to_write = (self.bytes.len() - self.written).min(buf.remaining());
if bytes_to_write > 0 {
let end = self.written + bytes_to_write;
buf.put_slice(&self.bytes[self.written..end]);
self.written = end;
}
std::task::Poll::Ready(Ok(()))
}
}
#[instrument(name = "Validate media", skip(bytes))]
pub(crate) async fn validate_bytes(
bytes: Bytes,
2022-03-28 04:27:07 +00:00
prescribed_format: Option<ImageFormat>,
2022-03-29 16:04:56 +00:00
enable_silent_video: bool,
enable_full_video: bool,
video_codec: VideoCodec,
audio_codec: Option<AudioCodec>,
validate: bool,
2021-10-23 17:35:07 +00:00
) -> Result<(ValidInputType, impl AsyncRead + Unpin), Error> {
let input_type =
if let Some(input_type) = crate::ffmpeg::input_type_bytes(bytes.clone()).await? {
input_type
} else {
crate::magick::input_type_bytes(bytes.clone()).await?
};
if !validate {
2021-10-23 17:35:07 +00:00
return Ok((input_type, Either::left(UnvalidatedBytes::new(bytes))));
}
match (prescribed_format, input_type) {
2022-03-29 16:04:56 +00:00
(_, ValidInputType::Gif) => {
if !(enable_silent_video || enable_full_video) {
2022-03-29 16:04:56 +00:00
return Err(UploadError::SilentVideoDisabled.into());
}
Ok((
2022-10-01 01:00:14 +00:00
ValidInputType::from_video_codec(video_codec),
2022-03-29 16:04:56 +00:00
Either::right(Either::left(
crate::ffmpeg::trancsocde_bytes(
bytes,
InputFormat::Gif,
false,
video_codec,
audio_codec,
)
.await?,
2022-03-29 16:04:56 +00:00
)),
))
}
(_, ValidInputType::Mp4) => {
if !(enable_silent_video || enable_full_video) {
2022-03-29 16:04:56 +00:00
return Err(UploadError::SilentVideoDisabled.into());
}
Ok((
2022-10-01 01:00:14 +00:00
ValidInputType::from_video_codec(video_codec),
2022-03-29 16:04:56 +00:00
Either::right(Either::left(
crate::ffmpeg::trancsocde_bytes(
bytes,
InputFormat::Mp4,
enable_full_video,
video_codec,
audio_codec,
)
.await?,
)),
))
}
(_, ValidInputType::Webm) => {
if !(enable_silent_video || enable_full_video) {
return Err(UploadError::SilentVideoDisabled.into());
}
Ok((
2022-10-01 01:00:14 +00:00
ValidInputType::from_video_codec(video_codec),
Either::right(Either::left(
crate::ffmpeg::trancsocde_bytes(
bytes,
InputFormat::Webm,
enable_full_video,
video_codec,
audio_codec,
)
.await?,
2022-03-29 16:04:56 +00:00
)),
))
}
2022-03-28 04:27:07 +00:00
(Some(ImageFormat::Jpeg) | None, ValidInputType::Jpeg) => Ok((
2021-10-23 17:35:07 +00:00
ValidInputType::Jpeg,
2021-10-21 01:13:39 +00:00
Either::right(Either::right(Either::left(
crate::exiftool::clear_metadata_bytes_read(bytes)?,
))),
)),
2022-03-28 04:27:07 +00:00
(Some(ImageFormat::Png) | None, ValidInputType::Png) => Ok((
2021-10-23 17:35:07 +00:00
ValidInputType::Png,
2021-10-21 01:13:39 +00:00
Either::right(Either::right(Either::left(
crate::exiftool::clear_metadata_bytes_read(bytes)?,
))),
)),
2022-03-28 04:27:07 +00:00
(Some(ImageFormat::Webp) | None, ValidInputType::Webp) => Ok((
2021-10-23 17:35:07 +00:00
ValidInputType::Webp,
2021-10-21 01:13:39 +00:00
Either::right(Either::right(Either::right(Either::left(
crate::magick::clear_metadata_bytes_read(bytes)?,
)))),
)),
(Some(format), _) => Ok((
2021-10-23 17:35:07 +00:00
ValidInputType::from_format(format),
2021-10-21 01:13:39 +00:00
Either::right(Either::right(Either::right(Either::right(
crate::magick::convert_bytes_read(bytes, format)?,
)))),
)),
}
}