1use http::HeaderMap;
2
3use crate::config::Config;
4use crate::error::TusError;
5use crate::proto::{HDR_TUS_RESUMABLE, TUS_VERSION};
6
7pub fn check_tus_resumable(headers: &HeaderMap) -> Result<(), TusError> {
9 match headers.get(HDR_TUS_RESUMABLE) {
10 None => Err(TusError::MissingTusResumable),
11 Some(v) => {
12 let s = v.to_str().unwrap_or("");
13 if s == TUS_VERSION {
14 Ok(())
15 } else {
16 Err(TusError::UnsupportedVersion {
17 version: s.to_string(),
18 })
19 }
20 }
21 }
22}
23
24pub fn parse_upload_offset(headers: &HeaderMap) -> Result<u64, TusError> {
26 headers
27 .get(crate::proto::HDR_UPLOAD_OFFSET)
28 .ok_or(TusError::MissingUploadOffset)?
29 .to_str()
30 .ok()
31 .and_then(|s| s.parse::<u64>().ok())
32 .ok_or(TusError::MissingUploadOffset)
33}
34
35pub fn parse_upload_length(headers: &HeaderMap) -> Result<Option<u64>, TusError> {
37 match headers.get(crate::proto::HDR_UPLOAD_LENGTH) {
38 None => Ok(None),
39 Some(v) => v
40 .to_str()
41 .ok()
42 .and_then(|s| s.parse::<u64>().ok())
43 .map(Some)
44 .ok_or_else(|| TusError::InvalidMetadata("invalid Upload-Length value".into())),
45 }
46}
47
48pub fn has_defer_length(headers: &HeaderMap) -> bool {
50 headers
51 .get(crate::proto::HDR_UPLOAD_DEFER_LENGTH)
52 .and_then(|v| v.to_str().ok())
53 .map(|s| s.trim() == "1")
54 .unwrap_or(false)
55}
56
57pub fn u64_header(n: u64) -> http::HeaderValue {
59 let s = n.to_string();
60 http::HeaderValue::try_from(s.as_str()).unwrap_or_else(|_| http::HeaderValue::from_static("0"))
61}
62
63pub(crate) fn request_base_url(config: &Config, headers: &HeaderMap) -> String {
65 if let Some(ref base) = config.base_url {
66 return base.trim_end_matches('/').to_string();
67 }
68 let scheme = if config.trust_forwarded_headers {
69 headers
70 .get("x-forwarded-proto")
71 .and_then(|v| v.to_str().ok())
72 .and_then(|s| s.split(',').next().map(str::trim))
73 .filter(|s| !s.is_empty())
74 .unwrap_or("http")
75 } else {
76 "http"
77 };
78 let host = if config.trust_forwarded_headers {
79 headers
80 .get("x-forwarded-host")
81 .or_else(|| headers.get("host"))
82 .and_then(|v| v.to_str().ok())
83 .map(|s| s.split(',').next().unwrap_or(s).trim())
84 .filter(|s| !s.is_empty())
85 .unwrap_or("localhost")
86 } else {
87 headers
88 .get("host")
89 .and_then(|v| v.to_str().ok())
90 .unwrap_or("localhost")
91 };
92 format!("{scheme}://{host}")
93}
94
95pub fn static_header(s: &'static str) -> http::HeaderValue {
97 http::HeaderValue::from_static(s)
98}