1use std::convert::TryFrom;
2use std::fmt::Display;
3use std::str::FromStr;
4
5use headers::Header;
6use http::header::{HeaderName, HeaderValue};
7use url::Url;
8
9use crate::fs::DavMetaData;
10
11pub static DEPTH: HeaderName = HeaderName::from_static("depth");
12pub static TIMEOUT: HeaderName = HeaderName::from_static("timeout");
13pub static OVERWRITE: HeaderName = HeaderName::from_static("overwrite");
14pub static DESTINATION: HeaderName = HeaderName::from_static("destination");
15pub static ETAG: HeaderName = HeaderName::from_static("etag");
16pub static IF_RANGE: HeaderName = HeaderName::from_static("if-range");
17pub static IF_MATCH: HeaderName = HeaderName::from_static("if-match");
18pub static IF_NONE_MATCH: HeaderName = HeaderName::from_static("if-none-match");
19pub static X_UPDATE_RANGE: HeaderName = HeaderName::from_static("x-update-range");
20pub static IF: HeaderName = HeaderName::from_static("if");
21pub static CONTENT_LANGUAGE: HeaderName = HeaderName::from_static("content-language");
22
23fn one<'i, I>(values: &mut I) -> Result<&'i HeaderValue, headers::Error>
25where
26 I: Iterator<Item = &'i HeaderValue>,
27{
28 let v = values.next().ok_or_else(invalid)?;
29 if values.next().is_some() {
30 Err(invalid())
31 } else {
32 Ok(v)
33 }
34}
35
36fn invalid() -> headers::Error {
38 headers::Error::invalid()
39}
40
41fn map_invalid(_e: impl std::error::Error) -> headers::Error {
43 headers::Error::invalid()
44}
45
46macro_rules! header {
47 ($tname:ident, $hname:ident, $sname:expr_2021) => {
48 pub static $hname: HeaderName = HeaderName::from_static($sname);
49
50 #[derive(Debug, Clone, PartialEq)]
51 pub struct $tname(pub String);
52
53 impl Header for $tname {
54 fn name() -> &'static HeaderName {
55 &$hname
56 }
57
58 fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
59 where
60 I: Iterator<Item = &'i HeaderValue>,
61 {
62 one(values)?
63 .to_str()
64 .map(|x| $tname(x.to_owned()))
65 .map_err(map_invalid)
66 }
67
68 fn encode<E>(&self, values: &mut E)
69 where
70 E: Extend<HeaderValue>,
71 {
72 let value = HeaderValue::from_str(&self.0).unwrap();
73 values.extend(std::iter::once(value))
74 }
75 }
76 };
77}
78
79header!(ContentType, CONTENT_TYPE, "content-type");
80header!(ContentLocation, CONTENT_LOCATION, "content-location");
81header!(LockToken, LOCK_TOKEN, "lock-token");
82header!(XLitmus, X_LITMUS, "x-litmus");
83
84#[derive(Debug, Copy, Clone, PartialEq)]
86pub enum Depth {
87 Default,
89 Zero,
91 One,
93 Infinity,
95}
96
97impl Header for Depth {
98 fn name() -> &'static HeaderName {
99 &DEPTH
100 }
101
102 fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
103 where
104 I: Iterator<Item = &'i HeaderValue>,
105 {
106 let value = one(values)?;
107 match value.as_bytes() {
108 b"0" => Ok(Depth::Zero),
109 b"1" => Ok(Depth::One),
110 b"infinity" | b"Infinity" => Ok(Depth::Infinity),
111 _ => Err(invalid()),
112 }
113 }
114
115 fn encode<E>(&self, values: &mut E)
116 where
117 E: Extend<HeaderValue>,
118 {
119 let value = match *self {
120 Depth::Default => "",
121 Depth::Zero => "0",
122 Depth::One => "1",
123 Depth::Infinity => "Infinity",
124 };
125 values.extend(std::iter::once(HeaderValue::from_static(value)));
126 }
127}
128
129#[derive(Debug, Clone, PartialEq)]
131pub struct ContentLanguage(headers::Vary);
132
133impl ContentLanguage {
134 #[allow(dead_code)]
135 pub fn iter_langs(&self) -> impl Iterator<Item = &str> {
136 self.0.iter_strs()
137 }
138}
139
140impl TryFrom<&str> for ContentLanguage {
141 type Error = headers::Error;
142
143 fn try_from(value: &str) -> Result<Self, Self::Error> {
144 let value = HeaderValue::from_str(value).map_err(map_invalid)?;
145 let mut values = std::iter::once(&value);
146 ContentLanguage::decode(&mut values)
147 }
148}
149
150impl Header for ContentLanguage {
151 fn name() -> &'static HeaderName {
152 &CONTENT_LANGUAGE
153 }
154
155 fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
156 where
157 I: Iterator<Item = &'i HeaderValue>,
158 {
159 let h = headers::Vary::decode(values)?;
160 for lang in h.iter_strs() {
161 let lang = lang.as_bytes();
162 let ok = lang.len() == 2 || (lang.len() > 4 && lang[2] == b'-');
164 if !ok {
165 return Err(invalid());
166 }
167 }
168 Ok(ContentLanguage(h))
169 }
170
171 fn encode<E>(&self, values: &mut E)
172 where
173 E: Extend<HeaderValue>,
174 {
175 self.0.encode(values)
176 }
177}
178
179#[derive(Debug, Clone, PartialEq)]
180pub enum DavTimeout {
181 Seconds(u32),
182 Infinite,
183}
184
185#[derive(Debug, Clone)]
186pub struct Timeout(pub Vec<DavTimeout>);
187
188impl Header for Timeout {
189 fn name() -> &'static HeaderName {
190 &TIMEOUT
191 }
192
193 fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
194 where
195 I: Iterator<Item = &'i HeaderValue>,
196 {
197 let value = one(values)?;
198 let mut v = Vec::new();
199 let words = value.to_str().map_err(map_invalid)?.split(',');
200 for word in words {
201 let w = match word {
202 "Infinite" => DavTimeout::Infinite,
203 _ if word.starts_with("Second-") => {
204 let num = &word[7..];
205 match num.parse::<u32>() {
206 Err(_) => return Err(invalid()),
207 Ok(n) => DavTimeout::Seconds(n),
208 }
209 }
210 _ => return Err(invalid()),
211 };
212 v.push(w);
213 }
214 Ok(Timeout(v))
215 }
216
217 fn encode<E>(&self, values: &mut E)
218 where
219 E: Extend<HeaderValue>,
220 {
221 let mut first = false;
222 let mut value = String::new();
223 for s in &self.0 {
224 if !first {
225 value.push_str(", ");
226 }
227 first = false;
228 match *s {
229 DavTimeout::Seconds(n) => value.push_str(&format!("Second-{n}")),
230 DavTimeout::Infinite => value.push_str("Infinite"),
231 }
232 }
233 values.extend(std::iter::once(HeaderValue::from_str(&value).unwrap()));
234 }
235}
236
237#[derive(Debug, Clone, PartialEq)]
238pub struct Destination(pub String);
239
240impl Header for Destination {
241 fn name() -> &'static HeaderName {
242 &DESTINATION
243 }
244
245 fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
246 where
247 I: Iterator<Item = &'i HeaderValue>,
248 {
249 let s = one(values)?.to_str().map_err(map_invalid)?;
250 if s.starts_with('/') {
251 return Ok(Destination(s.to_string()));
252 }
253 if let Ok(url) = s.parse::<Url>() {
254 return Ok(Destination(url.path().to_string()));
255 }
256 Err(invalid())
257 }
258
259 fn encode<E>(&self, values: &mut E)
260 where
261 E: Extend<HeaderValue>,
262 {
263 values.extend(std::iter::once(HeaderValue::from_str(&self.0).unwrap()));
264 }
265}
266
267#[derive(Debug, Clone, PartialEq)]
268pub struct Overwrite(pub bool);
269
270impl Header for Overwrite {
271 fn name() -> &'static HeaderName {
272 &OVERWRITE
273 }
274
275 fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
276 where
277 I: Iterator<Item = &'i HeaderValue>,
278 {
279 let line = one(values)?;
280 match line.as_bytes() {
281 b"F" => Ok(Overwrite(false)),
282 b"T" => Ok(Overwrite(true)),
283 _ => Err(invalid()),
284 }
285 }
286
287 fn encode<E>(&self, values: &mut E)
288 where
289 E: Extend<HeaderValue>,
290 {
291 let value = match self.0 {
292 true => "T",
293 false => "F",
294 };
295 values.extend(std::iter::once(HeaderValue::from_static(value)));
296 }
297}
298
299#[derive(Debug, Clone)]
300pub struct ETag {
301 tag: String,
302 weak: bool,
303}
304
305impl ETag {
306 #[allow(dead_code)]
307 pub fn new(weak: bool, t: impl Into<String>) -> Result<ETag, headers::Error> {
308 let t = t.into();
309 if t.contains('\"') {
310 Err(invalid())
311 } else {
312 let w = if weak { "W/" } else { "" };
313 Ok(ETag {
314 tag: format!("{w}\"{t}\""),
315 weak,
316 })
317 }
318 }
319
320 pub fn from_meta(meta: &dyn DavMetaData) -> Option<ETag> {
321 let tag = meta.etag()?;
322 Some(ETag {
323 tag: format!("\"{tag}\""),
324 weak: false,
325 })
326 }
327
328 #[allow(dead_code)]
329 pub fn is_weak(&self) -> bool {
330 self.weak
331 }
332}
333
334impl FromStr for ETag {
335 type Err = headers::Error;
336
337 fn from_str(t: &str) -> Result<Self, Self::Err> {
338 let (weak, s) = if let Some(t) = t.strip_prefix("W/") {
339 (true, t)
340 } else {
341 (false, t)
342 };
343 if s.starts_with('\"') && s.ends_with('\"') && !s[1..s.len() - 1].contains('\"') {
344 Ok(ETag {
345 tag: t.to_owned(),
346 weak,
347 })
348 } else {
349 Err(invalid())
350 }
351 }
352}
353
354impl TryFrom<&HeaderValue> for ETag {
355 type Error = headers::Error;
356
357 fn try_from(value: &HeaderValue) -> Result<Self, Self::Error> {
358 let s = value.to_str().map_err(map_invalid)?;
359 ETag::from_str(s)
360 }
361}
362
363impl Display for ETag {
364 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
365 write!(f, "\"{}\"", self.tag)
366 }
367}
368
369impl PartialEq for ETag {
370 fn eq(&self, other: &Self) -> bool {
371 !self.weak && !other.weak && self.tag == other.tag
372 }
373}
374
375impl Header for ETag {
376 fn name() -> &'static HeaderName {
377 &ETAG
378 }
379
380 fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
381 where
382 I: Iterator<Item = &'i HeaderValue>,
383 {
384 let value = one(values)?;
385 ETag::try_from(value)
386 }
387
388 fn encode<E>(&self, values: &mut E)
389 where
390 E: Extend<HeaderValue>,
391 {
392 values.extend(std::iter::once(HeaderValue::from_str(&self.tag).unwrap()));
393 }
394}
395
396#[derive(Debug, Clone, PartialEq)]
397pub enum IfRange {
398 ETag(ETag),
399 Date(headers::Date),
400}
401
402impl Header for IfRange {
403 fn name() -> &'static HeaderName {
404 &IF_RANGE
405 }
406
407 fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
408 where
409 I: Iterator<Item = &'i HeaderValue>,
410 {
411 let value = one(values)?;
412
413 let mut iter = std::iter::once(value);
414 if let Ok(tm) = headers::Date::decode(&mut iter) {
415 return Ok(IfRange::Date(tm));
416 }
417
418 let mut iter = std::iter::once(value);
419 if let Ok(et) = ETag::decode(&mut iter) {
420 return Ok(IfRange::ETag(et));
421 }
422
423 Err(invalid())
424 }
425
426 fn encode<E>(&self, values: &mut E)
427 where
428 E: Extend<HeaderValue>,
429 {
430 match *self {
431 IfRange::Date(ref d) => d.encode(values),
432 IfRange::ETag(ref t) => t.encode(values),
433 }
434 }
435}
436
437#[derive(Debug, Clone, PartialEq)]
438pub enum ETagList {
439 Tags(Vec<ETag>),
440 Star,
441}
442
443#[derive(Debug, Clone, PartialEq)]
444pub struct IfMatch(pub ETagList);
445
446#[derive(Debug, Clone, PartialEq)]
447pub struct IfNoneMatch(pub ETagList);
448
449fn decode_etaglist<'i, I>(values: &mut I) -> Result<ETagList, headers::Error>
453where
454 I: Iterator<Item = &'i HeaderValue>,
455{
456 let mut v = Vec::new();
457 let mut count = 0usize;
458 for value in values {
459 let s = value.to_str().map_err(map_invalid)?;
460 if s.trim() == "*" {
461 return Ok(ETagList::Star);
462 }
463 for t in s.split(',') {
464 if let Ok(t) = ETag::from_str(t.trim()) {
466 v.push(t);
467 }
468 }
469 count += 1;
470 }
471 if count != 0 {
472 Ok(ETagList::Tags(v))
473 } else {
474 Err(invalid())
475 }
476}
477
478fn encode_etaglist<E>(m: &ETagList, values: &mut E)
479where
480 E: Extend<HeaderValue>,
481{
482 let value = match *m {
483 ETagList::Star => "*".to_string(),
484 ETagList::Tags(ref t) => t
485 .iter()
486 .map(|t| t.tag.as_str())
487 .collect::<Vec<&str>>()
488 .join(", "),
489 };
490 values.extend(std::iter::once(HeaderValue::from_str(&value).unwrap()));
491}
492
493impl Header for IfMatch {
494 fn name() -> &'static HeaderName {
495 &IF_MATCH
496 }
497
498 fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
499 where
500 I: Iterator<Item = &'i HeaderValue>,
501 {
502 Ok(IfMatch(decode_etaglist(values)?))
503 }
504
505 fn encode<E>(&self, values: &mut E)
506 where
507 E: Extend<HeaderValue>,
508 {
509 encode_etaglist(&self.0, values)
510 }
511}
512
513impl Header for IfNoneMatch {
514 fn name() -> &'static HeaderName {
515 &IF_NONE_MATCH
516 }
517
518 fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
519 where
520 I: Iterator<Item = &'i HeaderValue>,
521 {
522 Ok(IfNoneMatch(decode_etaglist(values)?))
523 }
524
525 fn encode<E>(&self, values: &mut E)
526 where
527 E: Extend<HeaderValue>,
528 {
529 encode_etaglist(&self.0, values)
530 }
531}
532
533#[derive(Debug, Clone, PartialEq)]
534pub enum XUpdateRange {
535 FromTo(u64, u64),
536 AllFrom(u64),
537 Last(u64),
538 Append,
539}
540
541impl Header for XUpdateRange {
542 fn name() -> &'static HeaderName {
543 &X_UPDATE_RANGE
544 }
545
546 fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
547 where
548 I: Iterator<Item = &'i HeaderValue>,
549 {
550 let mut s = one(values)?.to_str().map_err(map_invalid)?;
551 if s == "append" {
552 return Ok(XUpdateRange::Append);
553 }
554 if !s.starts_with("bytes=") {
555 return Err(invalid());
556 }
557 s = &s[6..];
558
559 let nums = s.split('-').collect::<Vec<&str>>();
560 if nums.len() != 2 {
561 return Err(invalid());
562 }
563 if !nums[0].is_empty() && !nums[1].is_empty() {
564 return Ok(XUpdateRange::FromTo(
565 (nums[0]).parse::<u64>().map_err(map_invalid)?,
566 (nums[1]).parse::<u64>().map_err(map_invalid)?,
567 ));
568 }
569 if !nums[0].is_empty() {
570 return Ok(XUpdateRange::AllFrom(
571 (nums[0]).parse::<u64>().map_err(map_invalid)?,
572 ));
573 }
574 if !nums[1].is_empty() {
575 return Ok(XUpdateRange::Last(
576 (nums[1]).parse::<u64>().map_err(map_invalid)?,
577 ));
578 }
579 Err(invalid())
580 }
581
582 fn encode<E>(&self, values: &mut E)
583 where
584 E: Extend<HeaderValue>,
585 {
586 let value = match *self {
587 XUpdateRange::Append => "append".to_string(),
588 XUpdateRange::FromTo(b, e) => format!("{b}-{e}"),
589 XUpdateRange::AllFrom(b) => format!("{b}-"),
590 XUpdateRange::Last(e) => format!("-{e}"),
591 };
592 values.extend(std::iter::once(HeaderValue::from_str(&value).unwrap()));
593 }
594}
595
596#[derive(Debug, Clone, PartialEq)]
598pub struct If(pub Vec<IfList>);
599
600#[derive(Debug, Clone, PartialEq)]
602pub struct IfList {
603 pub resource_tag: Option<url::Url>,
604 pub conditions: Vec<IfCondition>,
605}
606
607impl IfList {
609 fn new() -> IfList {
610 IfList {
611 resource_tag: None,
612 conditions: Vec::new(),
613 }
614 }
615 fn add(&mut self, not: bool, item: IfItem) {
616 self.conditions.push(IfCondition { not, item });
617 }
618}
619
620#[derive(Debug, Clone, PartialEq)]
622pub struct IfCondition {
623 pub not: bool,
624 pub item: IfItem,
625}
626#[derive(Debug, Clone, PartialEq)]
627pub enum IfItem {
628 StateToken(String),
629 ETag(ETag),
630}
631
632#[derive(Debug, Clone, PartialEq)]
634enum IfToken {
635 ListOpen,
636 ListClose,
637 Not,
638 Word(String),
639 Pointy(String),
640 ETag(ETag),
641 End,
642}
643
644#[derive(Debug, Clone, PartialEq)]
645enum IfState {
646 Start,
647 RTag,
648 List,
649 Not,
650 Bad,
651}
652
653fn is_whitespace(c: u8) -> bool {
655 b" \t\r\n".contains(&c)
656}
657fn is_special(c: u8) -> bool {
658 b"<>()[]".contains(&c)
659}
660
661fn trim_left(mut out: &'_ [u8]) -> &'_ [u8] {
662 while !out.is_empty() && is_whitespace(out[0]) {
663 out = &out[1..];
664 }
665 out
666}
667
668fn scan_until(buf: &[u8], c: u8) -> Result<(&[u8], &[u8]), headers::Error> {
670 let mut i = 1;
671 let mut quote = false;
672 while quote || buf[i] != c {
673 if buf.is_empty() || is_whitespace(buf[i]) {
674 return Err(invalid());
675 }
676 if buf[i] == b'"' {
677 quote = !quote;
678 }
679 i += 1
680 }
681 Ok((&buf[1..i], &buf[i + 1..]))
682}
683
684fn scan_word(buf: &[u8]) -> Result<(&[u8], &[u8]), headers::Error> {
686 for (i, &c) in buf.iter().enumerate() {
687 if is_whitespace(c) || is_special(c) || c < 32 {
688 if i == 0 {
689 return Err(invalid());
690 }
691 return Ok((&buf[..i], &buf[i..]));
692 }
693 }
694 Ok((buf, b""))
695}
696
697fn get_token(buf: &'_ [u8]) -> Result<(IfToken, &'_ [u8]), headers::Error> {
699 let buf = trim_left(buf);
700 if buf.is_empty() {
701 return Ok((IfToken::End, buf));
702 }
703 match buf[0] {
704 b'(' => Ok((IfToken::ListOpen, &buf[1..])),
705 b')' => Ok((IfToken::ListClose, &buf[1..])),
706 b'N' if buf.starts_with(b"Not") => Ok((IfToken::Not, &buf[3..])),
707 b'<' => {
708 let (tok, rest) = scan_until(buf, b'>')?;
709 let s = std::string::String::from_utf8(tok.to_vec()).map_err(map_invalid)?;
710 Ok((IfToken::Pointy(s), rest))
711 }
712 b'[' => {
713 let (tok, rest) = scan_until(buf, b']')?;
714 let s = std::str::from_utf8(tok).map_err(map_invalid)?;
715 Ok((IfToken::ETag(ETag::from_str(s)?), rest))
716 }
717 _ => {
718 let (tok, rest) = scan_word(buf)?;
719 if tok == b"Not" {
720 Ok((IfToken::Not, rest))
721 } else {
722 let s = std::string::String::from_utf8(tok.to_vec()).map_err(map_invalid)?;
723 Ok((IfToken::Word(s), rest))
724 }
725 }
726 }
727}
728
729impl Header for If {
730 fn name() -> &'static HeaderName {
731 &IF
732 }
733
734 fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
735 where
736 I: Iterator<Item = &'i HeaderValue>,
737 {
738 let mut if_lists = If(Vec::new());
740 let mut cur_list = IfList::new();
741
742 let mut state = IfState::Start;
743 let mut input = one(values)?.as_bytes();
744
745 loop {
746 let (tok, rest) = get_token(input)?;
747 input = rest;
748 state = match state {
749 IfState::Start => match tok {
750 IfToken::ListOpen => IfState::List,
751 IfToken::Pointy(url) => {
752 let u = url::Url::parse(&url).map_err(map_invalid)?;
753 cur_list.resource_tag = Some(u);
754 IfState::RTag
755 }
756 IfToken::End => {
757 if !if_lists.0.is_empty() {
758 break;
759 }
760 IfState::Bad
761 }
762 _ => IfState::Bad,
763 },
764 IfState::RTag => match tok {
765 IfToken::ListOpen => IfState::List,
766 _ => IfState::Bad,
767 },
768 IfState::List | IfState::Not => {
769 let not = state == IfState::Not;
770 match tok {
771 IfToken::Not => {
772 if not {
773 IfState::Bad
774 } else {
775 IfState::Not
776 }
777 }
778 IfToken::Pointy(stok) | IfToken::Word(stok) => {
779 if !stok.contains(':') {
782 IfState::Bad
783 } else {
784 cur_list.add(not, IfItem::StateToken(stok));
785 IfState::List
786 }
787 }
788 IfToken::ETag(etag) => {
789 cur_list.add(not, IfItem::ETag(etag));
790 IfState::List
791 }
792 IfToken::ListClose => {
793 if cur_list.conditions.is_empty() {
794 IfState::Bad
795 } else {
796 if_lists.0.push(cur_list);
797 cur_list = IfList::new();
798 IfState::Start
799 }
800 }
801 _ => IfState::Bad,
802 }
803 }
804 IfState::Bad => return Err(invalid()),
805 };
806 }
807 Ok(if_lists)
808 }
809
810 fn encode<E>(&self, values: &mut E)
811 where
812 E: Extend<HeaderValue>,
813 {
814 let value = "[If header]";
815 values.extend(std::iter::once(HeaderValue::from_static(value)));
816 }
817}
818
819#[cfg(test)]
820mod tests {
821 use super::*;
822
823 #[test]
824 fn if_header() {
825 let val = r#" <http://x.yz/> ([W/"etag"] Not <DAV:nope> ) (Not<urn:x>[W/"bla"] plain:word:123) "#;
832 let hdrval = HeaderValue::from_static(val);
833 let mut iter = std::iter::once(&hdrval);
834 let hdr = If::decode(&mut iter);
835 assert!(hdr.is_ok());
836 }
837
838 #[test]
839 fn etag_header() {
840 let t1 = ETag::from_str(r#"W/"12345""#).unwrap();
841 let t2 = ETag::from_str(r#"W/"12345""#).unwrap();
842 let t3 = ETag::from_str(r#""12346""#).unwrap();
843 let t4 = ETag::from_str(r#""12346""#).unwrap();
844 assert!(t1 != t2);
845 assert!(t2 != t3);
846 assert!(t3 == t4);
847 }
848}