fileloft-core 0.2.1

Framework-agnostic core for the tus.io resumable upload protocol
Documentation
use http::{HeaderMap, StatusCode};

use crate::{
    error::TusError,
    handler::{TusRequest, TusResponse},
    lock::SendLocker,
    proto::*,
    store::SendDataStore,
    util::static_header,
};

use super::TusHandler;

pub(super) async fn handle<S, L>(
    h: &TusHandler<S, L>,
    _req: &TusRequest,
) -> Result<TusResponse, TusError>
where
    S: SendDataStore + Send + Sync + 'static,
    L: SendLocker + Send + Sync + 'static,
{
    let mut headers = HeaderMap::new();

    // Advertise supported versions
    headers.insert(HDR_TUS_VERSION, static_header(TUS_VERSION));

    // Build the extension list from the current Config
    let ext = &h.config.extensions;
    let mut exts = Vec::new();
    if ext.creation {
        exts.push(EXT_CREATION);
    }
    if ext.creation_with_upload {
        exts.push(EXT_CREATION_WITH_UPLOAD);
    }
    if ext.creation_defer_length {
        exts.push(EXT_CREATION_DEFER_LENGTH);
    }
    if ext.expiration {
        exts.push(EXT_EXPIRATION);
    }
    if ext.checksum {
        exts.push(EXT_CHECKSUM);
    }
    if ext.checksum_trailer && CHECKSUM_TRAILER_IMPLEMENTED {
        exts.push(EXT_CHECKSUM_TRAILER);
    }
    if ext.termination {
        exts.push(EXT_TERMINATION);
    }
    if ext.concatenation {
        exts.push(EXT_CONCATENATION);
    }

    if !exts.is_empty() {
        let ext_str = exts.join(",");
        headers.insert(
            HDR_TUS_EXTENSION,
            ext_str
                .parse()
                .map_err(|_| TusError::Internal("bad extension header".into()))?,
        );
    }

    if ext.checksum {
        headers.insert(
            HDR_TUS_CHECKSUM_ALGORITHM,
            crate::checksum::algorithms_header()
                .parse()
                .map_err(|_| TusError::Internal("bad algorithm header".into()))?,
        );
    }

    if h.config.max_size > 0 {
        headers.insert(HDR_TUS_MAX_SIZE, crate::util::u64_header(h.config.max_size));
    }

    let cors = &h.config.cors;
    if cors.enabled {
        let methods = if h.config.enable_download {
            "OPTIONS,HEAD,GET,POST,PATCH,DELETE"
        } else {
            "OPTIONS,HEAD,POST,PATCH,DELETE"
        };
        headers.insert(
            HDR_ACCESS_CONTROL_ALLOW_METHODS,
            methods
                .parse()
                .map_err(|_| TusError::Internal("bad CORS methods header".into()))?,
        );

        let mut allow = String::from(
            "Tus-Resumable,Upload-Length,Upload-Offset,Upload-Metadata,\
             Upload-Defer-Length,Upload-Checksum,Upload-Concat,Content-Type",
        );
        for extra in &cors.extra_allow_headers {
            allow.push(',');
            allow.push_str(extra.trim());
        }
        headers.insert(
            HDR_ACCESS_CONTROL_ALLOW_HEADERS,
            allow
                .parse()
                .map_err(|_| TusError::Internal("bad CORS allow-headers".into()))?,
        );

        headers.insert(
            HDR_ACCESS_CONTROL_MAX_AGE,
            cors.max_age
                .to_string()
                .parse()
                .map_err(|_| TusError::Internal("bad CORS max-age".into()))?,
        );
    }

    Ok(h.response(StatusCode::NO_CONTENT, headers, bytes::Bytes::new()))
}