use bytes::Bytes;
use http::{HeaderMap, HeaderName, HeaderValue, StatusCode};
use crate::config::TUS_RESUMABLE;
pub const TUS_SUCCESS_RESPONSE_HEADERS: &[&str] = &[
"tus-resumable",
"tus-version",
"tus-extension",
"tus-max-size",
"tus-checksum-algorithm",
"upload-offset",
"upload-length",
"upload-defer-length",
"upload-concat",
"upload-expires",
"upload-metadata",
"location",
];
#[derive(Debug)]
#[non_exhaustive]
pub struct Response {
pub status: StatusCode,
pub headers: HeaderMap,
pub body: Bytes,
}
impl Response {
pub fn new(status: StatusCode) -> Self {
let mut headers = HeaderMap::new();
headers.insert("tus-resumable", HeaderValue::from_static(TUS_RESUMABLE));
Self {
status,
headers,
body: Bytes::new(),
}
}
#[must_use]
pub fn with_header(mut self, name: impl AsRef<str>, value: impl AsRef<str>) -> Self {
let name = name.as_ref();
match (
HeaderName::try_from(name),
HeaderValue::from_str(value.as_ref()),
) {
(Ok(n), Ok(v)) => {
self.headers.insert(n, v);
}
_ => {
tracing::warn!(header = %name, "dropping response header with invalid name or value");
}
}
self
}
#[must_use]
pub fn with_body(mut self, body: Bytes) -> Self {
self.body = body;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_includes_tus_resumable() {
let response = Response::new(StatusCode::CREATED);
assert_eq!(response.status, StatusCode::CREATED);
assert_eq!(
response.headers.get("tus-resumable").unwrap(),
TUS_RESUMABLE
);
}
#[test]
fn with_header_sets_value() {
let response = Response::new(StatusCode::OK)
.with_header("upload-offset", "42")
.with_header("location", "/files/abc");
assert_eq!(response.headers.get("upload-offset").unwrap(), "42");
assert_eq!(response.headers.get("location").unwrap(), "/files/abc");
}
#[test]
fn with_body_sets_body() {
let response = Response::new(StatusCode::OK).with_body(Bytes::from_static(b"hello"));
assert_eq!(response.body.as_ref(), b"hello");
}
}