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}