wayver's git archive


a simple self-hosted git server
git clone https://git.wayver.dev/bile

src/http/extractor.rs@32c6bed79b26b918b19bcaa6d2f5eaf797bbeb92

raw
Date Commit Message Author Files + -
2026-02-19 19:32 fixed issue where non-directory and dotfiles are treated as git repos wayverd 4 43 9
...

1use std::fmt;
2
3use serde::de::Error as _;
4use trim_in_place::TrimInPlace as _;
5
6pub(crate) struct Commit(pub String);
7
8impl fmt::Display for Commit {
9    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
10        self.0.fmt(f)
11    }
12}
13
14impl<'de> serde::Deserialize<'de> for Commit {
15    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
16    where
17        D: serde::Deserializer<'de>,
18    {
19        let mut value = String::deserialize(deserializer)?;
20
21        value.trim_in_place();
22
23        if value.is_empty() || value.starts_with('.') {
24            return Err(D::Error::custom("invalid commit ref"));
25        }
26
27        for c in value.bytes() {
28            if !c.is_ascii_hexdigit() {
29                return Err(D::Error::custom("invalid commit ref"));
30            }
31        }
32
33        Ok(Self(value))
34    }
35}
36
37pub(crate) struct Obj(pub String);
38
39impl fmt::Display for Obj {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        self.0.fmt(f)
42    }
43}
44
45impl<'de> serde::Deserialize<'de> for Obj {
46    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
47    where
48        D: serde::Deserializer<'de>,
49    {
50        let mut value = String::deserialize(deserializer)?;
51
52        value.trim_in_place();
53
54        if value.is_empty() {
55            return Err(D::Error::custom("invalid object ref"));
56        }
57
58        Ok(Self(value))
59    }
60}
61
62pub(crate) struct ObjectName(pub String);
63
64impl fmt::Display for ObjectName {
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66        self.0.fmt(f)
67    }
68}
69
70impl<'de> serde::Deserialize<'de> for ObjectName {
71    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
72    where
73        D: serde::Deserializer<'de>,
74    {
75        let mut value = String::deserialize(deserializer)?;
76
77        value.trim_in_place();
78
79        if value.is_empty() {
80            return Err(D::Error::custom("invalid object name"));
81        }
82
83        Ok(Self(value))
84    }
85}
86
87pub(crate) struct Ref(pub String);
88
89impl fmt::Display for Ref {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        self.0.fmt(f)
92    }
93}
94
95impl<'de> serde::Deserialize<'de> for Ref {
96    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
97    where
98        D: serde::Deserializer<'de>,
99    {
100        let mut value = String::deserialize(deserializer)?;
101
102        value.trim_in_place();
103
104        if value.is_empty() || value.starts_with('.') {
105            return Err(D::Error::custom("invalid ref"));
106        }
107
108        Ok(Self(value))
109    }
110}
111
112pub(crate) struct RepoName(pub String);
113
114impl fmt::Display for RepoName {
115    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116        self.0.fmt(f)
117    }
118}
119
120impl<'de> serde::Deserialize<'de> for RepoName {
121    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
122    where
123        D: serde::Deserializer<'de>,
124    {
125        let mut value = String::deserialize(deserializer)?;
126
127        value.trim_in_place();
128
129        if value.is_empty() || value.starts_with('.') {
130            return Err(D::Error::custom("invalid repo name"));
131        }
132
133        Ok(Self(value))
134    }
135}
136
137pub(crate) struct Tag(pub String);
138
139impl fmt::Display for Tag {
140    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141        self.0.fmt(f)
142    }
143}
144
145impl<'de> serde::Deserialize<'de> for Tag {
146    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
147    where
148        D: serde::Deserializer<'de>,
149    {
150        let mut value = String::deserialize(deserializer)?;
151
152        value.trim_in_place();
153
154        if value.is_empty() {
155            return Err(D::Error::custom("invalid tag"));
156        }
157
158        Ok(Self(value))
159    }
160}
161