Files
AstralRinth/apps/labrinth/src/util/actix.rs
Alejandro González f84f8c1c2b chore(clippy): enable and fix many stricter lints (#3783)
* chore(clippy): enable and fix many stricter lints

These ensure that the codebase uses more idiomatic, performant, and
concise language constructions.

* chore: make non-Clippy compiler warnings also deny by default
2025-06-14 00:10:12 +00:00

88 lines
2.5 KiB
Rust

use actix_web::test::TestRequest;
use bytes::{Bytes, BytesMut};
// Multipart functionality for actix
// Primarily for testing or some implementations of route-redirection
// (actix-test does not innately support multipart)
#[derive(Debug, Clone)]
pub struct MultipartSegment {
pub name: String,
pub filename: Option<String>,
pub content_type: Option<String>,
pub data: MultipartSegmentData,
}
#[derive(Debug, Clone)]
pub enum MultipartSegmentData {
Text(String),
Binary(Vec<u8>),
}
pub trait AppendsMultipart {
fn set_multipart(
self,
data: impl IntoIterator<Item = MultipartSegment>,
) -> Self;
}
impl AppendsMultipart for TestRequest {
fn set_multipart(
self,
data: impl IntoIterator<Item = MultipartSegment>,
) -> Self {
let (boundary, payload) = generate_multipart(data);
self.append_header((
"Content-Type",
format!("multipart/form-data; boundary={boundary}"),
))
.set_payload(payload)
}
}
pub fn generate_multipart(
data: impl IntoIterator<Item = MultipartSegment>,
) -> (String, Bytes) {
let mut boundary: String = String::from("----WebKitFormBoundary");
boundary.push_str(&rand::random::<u64>().to_string());
boundary.push_str(&rand::random::<u64>().to_string());
boundary.push_str(&rand::random::<u64>().to_string());
let mut payload = BytesMut::new();
for segment in data {
payload.extend_from_slice(
format!(
"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"",
boundary = boundary,
name = segment.name
)
.as_bytes(),
);
if let Some(filename) = &segment.filename {
payload.extend_from_slice(
format!("; filename=\"{filename}\"").as_bytes(),
);
}
if let Some(content_type) = &segment.content_type {
payload.extend_from_slice(
format!("\r\nContent-Type: {content_type}").as_bytes(),
);
}
payload.extend_from_slice(b"\r\n\r\n");
match &segment.data {
MultipartSegmentData::Text(text) => {
payload.extend_from_slice(text.as_bytes());
}
MultipartSegmentData::Binary(binary) => {
payload.extend_from_slice(binary);
}
}
payload.extend_from_slice(b"\r\n");
}
payload.extend_from_slice(format!("--{boundary}--\r\n").as_bytes());
(boundary, Bytes::from(payload))
}