http_async/path.rs
1use
2{
3 super::
4 {
5 KeyValuePair,
6 request::
7 {
8 Request,
9 },
10 },
11 async_std::
12 {
13 net::
14 {
15 TcpStream,
16 },
17 },
18 std::
19 {
20 fmt::
21 {
22 self,
23 Display,
24 },
25 },
26};
27
28/// Path and Query to a Resource.
29pub struct Path
30{
31 /// Path to a Resource.
32 pub path: String,
33 /// List of Query Key Value Pairs.
34 pub query: Vec < KeyValuePair >,
35}
36
37impl Path
38{
39 /// Try to parse Path from from Transmission Control Protocol Stream.
40 ///
41 /// # Arguments
42 /// * `stream` – Transmission Control Protocol Stream.
43 pub async fn parse
44 (
45 mut stream: &mut TcpStream,
46 querySeperator: char,
47 )
48 -> Option < Path >
49 {
50 let mut result = None;
51 let mut path = "".to_owned ( );
52 let mut key = "".to_owned ( );
53 let mut value = "".to_owned ( );
54 let mut query = Vec::new ( );
55 let mut state = PathState::Start;
56 while let Some ( char ) = Request::readChar ( &mut stream )
57 {
58 match char
59 {
60 ' '
61 => {
62 match state
63 {
64 | PathState::Value
65 | PathState::Key
66 => if !key.is_empty()
67 {
68 query
69 .push
70 (
71 KeyValuePair
72 {
73 key,
74 value,
75 }
76 );
77 },
78 PathState::Start
79 => {},
80 }
81 result
82 = Some
83 (
84 Path
85 {
86 path,
87 query,
88 }
89 );
90 break;
91 },
92 '?'
93 => match state
94 {
95 PathState::Start => state = PathState::Key,
96 PathState::Key => key.push ( char as char ),
97 PathState::Value => value.push ( char as char ),
98 },
99 '='
100 => match state
101 {
102 PathState::Start => path.push ( char as char ),
103 PathState::Key => state = PathState::Value,
104 PathState::Value => value.push ( char as char ),
105 },
106 '\r' | '\n'
107 => break,
108 _
109 => if char == querySeperator
110 {
111 match state
112 {
113 PathState::Start => path.push ( char as char ),
114 | PathState::Key
115 | PathState::Value
116 => {
117 state = PathState::Key;
118 if !key.is_empty()
119 {
120 query
121 .push
122 (
123 KeyValuePair
124 {
125 key: key.clone(),
126 value: value.clone(),
127 }
128 );
129 }
130 key = "".to_owned ( );
131 value = "".to_owned ( );
132 },
133 }
134 }
135 else
136 {
137 match state
138 {
139 PathState::Start => path.push ( char as char ),
140 PathState::Key => key.push ( char as char ),
141 PathState::Value => value.push ( char as char ),
142 }
143 },
144 }
145 }
146 result
147 }
148}
149
150impl Display for Path
151{
152 fn fmt
153 (
154 &self,
155 formatter: &mut fmt::Formatter<'_>
156 )
157 -> fmt::Result
158 {
159 formatter
160 .write_str
161 (
162 &format!
163 (
164 "{}{}",
165 &self
166 .path,
167 &if self
168 .query
169 .is_empty ( )
170 {
171 format!
172 (
173 "?{}",
174 self
175 .query
176 .iter()
177 .map
178 (
179 | entry |
180 format!
181 (
182 "{}={}",
183 entry.key,
184 entry.value,
185 )
186 )
187 .collect::< Vec < String > >()
188 .join ( "&" ),
189 )
190 }
191 else
192 {
193 "".to_owned()
194 },
195 )
196 )
197 }
198}
199
200/// State of the Parser parsing a Path.
201enum PathState
202{
203 Start,
204 Key,
205 Value,
206}