fileloft_core/config.rs
1use std::time::Duration;
2
3use crate::hooks::HookConfig;
4
5/// Cross-origin resource sharing settings (tus clients in browsers).
6#[derive(Debug, Clone)]
7pub struct CorsConfig {
8 /// When false, no CORS headers are added.
9 pub enabled: bool,
10 /// `Access-Control-Allow-Origin` value (e.g. `"*"` or `"https://example.com"`).
11 pub allow_origin: String,
12 /// `Access-Control-Allow-Credentials`.
13 pub allow_credentials: bool,
14 /// Extra header names merged into `Access-Control-Allow-Headers` (tus defaults are always included).
15 pub extra_allow_headers: Vec<String>,
16 /// Extra header names merged into `Access-Control-Expose-Headers` (tus defaults are always included).
17 pub extra_expose_headers: Vec<String>,
18 /// `Access-Control-Max-Age` for preflight (seconds).
19 pub max_age: u64,
20}
21
22impl Default for CorsConfig {
23 fn default() -> Self {
24 Self {
25 enabled: false,
26 allow_origin: "*".to_string(),
27 allow_credentials: false,
28 extra_allow_headers: Vec::new(),
29 extra_expose_headers: Vec::new(),
30 max_age: 86400,
31 }
32 }
33}
34
35/// Runtime flags controlling which tus protocol extensions are active.
36///
37/// These are runtime config, not Cargo features, so one compiled binary can
38/// serve any combination without recompilation.
39#[derive(Debug, Clone)]
40pub struct Extensions {
41 /// POST to create a new upload (required by most clients).
42 pub creation: bool,
43 /// POST with body to combine creation and first chunk.
44 pub creation_with_upload: bool,
45 /// Allow `Upload-Defer-Length: 1` to defer declaring size at creation.
46 pub creation_defer_length: bool,
47 /// Attach expiry timestamps to incomplete uploads.
48 pub expiration: bool,
49 /// How long incomplete uploads live before expiry. Used when `expiration = true`.
50 pub expiration_ttl: Option<Duration>,
51 /// Validate chunk integrity via `Upload-Checksum` header.
52 pub checksum: bool,
53 /// Accept checksum in HTTP trailers (requires HTTP/1.1 chunked or HTTP/2).
54 pub checksum_trailer: bool,
55 /// Allow clients to DELETE uploads.
56 pub termination: bool,
57 /// Allow parallel partial uploads assembled into a final upload.
58 pub concatenation: bool,
59 /// After a successful `final` concatenation, delete partial upload resources.
60 pub cleanup_concat_partials: bool,
61}
62
63impl Default for Extensions {
64 fn default() -> Self {
65 Self {
66 creation: true,
67 creation_with_upload: true,
68 creation_defer_length: true,
69 expiration: false,
70 expiration_ttl: None,
71 checksum: true,
72 checksum_trailer: false,
73 termination: true,
74 concatenation: false,
75 cleanup_concat_partials: false,
76 }
77 }
78}
79
80/// Top-level handler configuration.
81#[derive(Debug, Clone)]
82pub struct Config {
83 /// URL path prefix where upload resources are rooted, e.g. `"/files/"`.
84 /// Used to build the `Location` header value on POST responses.
85 pub base_path: String,
86 /// Optional absolute base URL override (e.g. `"https://uploads.example.com"`).
87 /// When `None` the handler builds the Location from the request's `Host` header.
88 pub base_url: Option<String>,
89 /// Maximum allowed `Upload-Length` in bytes. `0` means no server-imposed limit.
90 pub max_size: u64,
91 /// Enabled protocol extensions.
92 pub extensions: Extensions,
93 /// How long to wait when acquiring a per-upload lock before returning 408.
94 pub lock_timeout: Duration,
95 /// CORS headers on responses.
96 pub cors: CorsConfig,
97 /// When `base_url` is unset, use `X-Forwarded-Proto` / `X-Forwarded-Host` to build absolute
98 /// URLs (e.g. behind TLS termination). **Only enable when this service is not directly exposed
99 /// to untrusted clients** (forwarded headers can be spoofed).
100 pub trust_forwarded_headers: bool,
101 /// Hook callbacks and event-channel configuration.
102 pub hooks: HookConfig,
103 /// Allow HTTP GET on upload URLs to download completed data (tus-style downloads).
104 /// When `false`, GET returns 405.
105 pub enable_download: bool,
106}
107
108impl Default for Config {
109 fn default() -> Self {
110 Self {
111 base_path: "/files/".to_string(),
112 base_url: None,
113 max_size: 0,
114 extensions: Extensions::default(),
115 lock_timeout: Duration::from_secs(20),
116 cors: CorsConfig::default(),
117 trust_forwarded_headers: false,
118 hooks: HookConfig::default(),
119 enable_download: false,
120 }
121 }
122}