1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 //! HTTP [`URI`].
15 //!
16 //! URI references are used to target requests, indicate redirects, and define
17 //! relationships.
18 //!
19 //! [`URI`]: https://httpwg.org/specs/rfc9110.html#uri.references
20 
21 mod percent_encoding;
22 
23 use core::convert::{Infallible, TryFrom, TryInto};
24 
25 pub use percent_encoding::PercentEncoder;
26 
27 use crate::error::{ErrorKind, HttpError};
28 
29 // Maximum uri length.
30 const MAX_URI_LEN: usize = (u16::MAX - 1) as usize;
31 
32 /// HTTP [`URI`] implementation.
33 ///
34 /// The complete structure of the uri is as follows:
35 ///
36 /// ```text
37 /// | scheme://authority path ?query |
38 /// ```
39 ///
40 /// `URI` currently only supports `HTTP` and `HTTPS` schemes.
41 ///
42 /// According to [RFC9110, Section 4.2], the userinfo parameter before authority
43 /// is forbidden. Fragment information in query is not stored in uri.
44 ///
45 /// So, the `URI` shown below is illegal:
46 ///
47 /// ```text
48 /// http://username:password@example.com:80/
49 /// ```
50 ///
51 /// [`URI`]: https://httpwg.org/specs/rfc9110.html#uri.references
52 /// [RFC9110, Section 4.2]: https://httpwg.org/specs/rfc9110.html#uri.schemes
53 ///
54 /// # Examples
55 ///
56 /// ```
57 /// use ylong_http::request::uri::Uri;
58 ///
59 /// let uri = Uri::builder()
60 ///     .scheme("http")
61 ///     .authority("example.com:80")
62 ///     .path("/foo")
63 ///     .query("a=1")
64 ///     .build()
65 ///     .unwrap();
66 ///
67 /// assert_eq!(uri.scheme().unwrap().as_str(), "http");
68 /// assert_eq!(uri.host().unwrap().as_str(), "example.com");
69 /// assert_eq!(uri.port().unwrap().as_str(), "80");
70 /// assert_eq!(uri.path().unwrap().as_str(), "/foo");
71 /// assert_eq!(uri.query().unwrap().as_str(), "a=1");
72 /// assert_eq!(uri.to_string(), "http://example.com:80/foo?a=1");
73 ///
74 /// let uri = Uri::from_bytes(b"http://example.com:80/foo?a=1").unwrap();
75 /// assert_eq!(uri.to_string(), "http://example.com:80/foo?a=1");
76 /// ```
77 #[derive(Clone, Debug, Default)]
78 pub struct Uri {
79     /// The scheme can be `None` when the relative uri is used.
80     scheme: Option<Scheme>,
81 
82     /// The authority can be `None` when the relative uri is used.
83     authority: Option<Authority>,
84 
85     /// The path can be `None` when the path is "/".
86     path: Option<Path>,
87 
88     /// The query can be `None` when the query is not set.
89     query: Option<Query>,
90 }
91 
92 impl Uri {
93     /// Creates an HTTP-compliant default `Uri` with `Path` set to '/'.
http() -> Uri94     pub(crate) fn http() -> Uri {
95         Uri {
96             scheme: None,
97             authority: None,
98             path: Path::from_bytes(b"/").ok(),
99             query: None,
100         }
101     }
102 
103     /// Creates a new default [`UriBuilder`].
104     ///
105     /// [`UriBuilder`]: UriBuilder
106     ///
107     /// # Examples
108     ///
109     /// ```
110     /// use ylong_http::request::uri::Uri;
111     ///
112     /// let builder = Uri::builder();
113     /// ```
builder() -> UriBuilder114     pub fn builder() -> UriBuilder {
115         UriBuilder::new()
116     }
117 
118     /// Gets a immutable reference to `Scheme`.
119     ///
120     /// Returns `None` if there is no `Scheme`.
121     ///
122     /// # Examples
123     ///
124     /// ```
125     /// use ylong_http::request::uri::Uri;
126     ///
127     /// let uri = Uri::from_bytes(b"http://example.com:80/foo?a=1").unwrap();
128     /// assert_eq!(uri.scheme().unwrap().as_str(), "http");
129     /// ```
scheme(&self) -> Option<&Scheme>130     pub fn scheme(&self) -> Option<&Scheme> {
131         self.scheme.as_ref()
132     }
133 
134     /// Gets a immutable reference to `Authority`.
135     ///
136     /// Returns `None` if there is no `Authority`.
137     ///
138     /// # Examples
139     ///
140     /// ```
141     /// use ylong_http::request::uri::Uri;
142     ///
143     /// let uri = Uri::from_bytes(b"http://example.com:80/foo?a=1").unwrap();
144     /// let authority = uri.authority().unwrap();
145     /// assert_eq!(authority.host().as_str(), "example.com");
146     /// assert_eq!(authority.port().unwrap().as_str(), "80");
147     /// ```
authority(&self) -> Option<&Authority>148     pub fn authority(&self) -> Option<&Authority> {
149         self.authority.as_ref()
150     }
151 
152     /// Gets a immutable reference to `Host`.
153     ///
154     /// Returns `None` if there is no `Host`.
155     ///
156     /// # Examples
157     ///
158     /// ```
159     /// use ylong_http::request::uri::Uri;
160     ///
161     /// let uri = Uri::from_bytes(b"http://example.com:80/foo?a=1").unwrap();
162     /// assert_eq!(uri.host().unwrap().as_str(), "example.com");
163     /// ```
host(&self) -> Option<&Host>164     pub fn host(&self) -> Option<&Host> {
165         self.authority.as_ref().map(|auth| auth.host())
166     }
167 
168     /// Gets a immutable reference to `Port`.
169     ///
170     /// Returns `None` if there is no `Port`.
171     ///
172     /// # Examples
173     ///
174     /// ```
175     /// use ylong_http::request::uri::Uri;
176     ///
177     /// let uri = Uri::from_bytes(b"http://example.com:80/foo?a=1").unwrap();
178     /// assert_eq!(uri.port().unwrap().as_str(), "80");
179     /// ```
port(&self) -> Option<&Port>180     pub fn port(&self) -> Option<&Port> {
181         self.authority.as_ref().and_then(|auth| auth.port())
182     }
183 
184     /// Gets a immutable reference to `Path`.
185     ///
186     /// Returns `None` if there is no `Path`.
187     ///
188     /// # Examples
189     ///
190     /// ```
191     /// use ylong_http::request::uri::Uri;
192     ///
193     /// let uri = Uri::from_bytes(b"http://example.com:80/foo?a=1").unwrap();
194     /// assert_eq!(uri.path().unwrap().as_str(), "/foo");
195     /// ```
path(&self) -> Option<&Path>196     pub fn path(&self) -> Option<&Path> {
197         self.path.as_ref()
198     }
199 
200     /// Gets a immutable reference to `Query`.
201     ///
202     /// Returns `None` if there is no `Query`.
203     ///
204     /// # Examples
205     ///
206     /// ```
207     /// use ylong_http::request::uri::Uri;
208     ///
209     /// let uri = Uri::from_bytes(b"http://example.com:80/foo?a=1").unwrap();
210     /// assert_eq!(uri.query().unwrap().as_str(), "a=1");
211     /// ```
query(&self) -> Option<&Query>212     pub fn query(&self) -> Option<&Query> {
213         self.query.as_ref()
214     }
215 
216     /// Converts a bytes slice into a `Uri`.
217     ///
218     /// # Examples
219     ///
220     /// ```
221     /// use ylong_http::request::uri::Uri;
222     ///
223     /// let uri = Uri::from_bytes(b"/foo?a=1").unwrap();
224     /// ```
from_bytes(bytes: &[u8]) -> Result<Self, HttpError>225     pub fn from_bytes(bytes: &[u8]) -> Result<Self, HttpError> {
226         if bytes.len() > MAX_URI_LEN {
227             return Err(InvalidUri::UriTooLong.into());
228         }
229         if bytes.is_empty() {
230             return Err(InvalidUri::InvalidFormat.into());
231         }
232         let (scheme, rest) = scheme_token(bytes)?;
233         let (authority, rest) = authority_token(rest)?;
234         let (path, rest) = path_token(rest)?;
235         let query = match rest.first() {
236             None => None,
237             Some(&b'?') => query_token(&rest[1..])?,
238             Some(&b'#') => None,
239             _ => return Err(InvalidUri::UriMissQuery.into()),
240         };
241         let result = Uri {
242             scheme,
243             authority,
244             path,
245             query,
246         };
247         validity_check(result).map_err(Into::into)
248     }
249 
250     /// Gets a `String`, which contains the path and query.
251     ///
252     /// Returns `None` if path and query are both empty.
253     ///
254     /// # Examples
255     ///
256     /// ```
257     /// use ylong_http::request::uri::Uri;
258     ///
259     /// let uri = Uri::from_bytes(b"http://example.com:80/foo?a=1").unwrap();
260     /// assert_eq!(uri.path_and_query().unwrap(), String::from("/foo?a=1"));
261     /// ```
path_and_query(&self) -> Option<String>262     pub fn path_and_query(&self) -> Option<String> {
263         let mut builder = String::new();
264         if let Some(path) = self.path() {
265             builder.push_str(path.as_str());
266         }
267         if let Some(query) = self.query() {
268             builder.push('?');
269             builder.push_str(query.as_str());
270         }
271         if builder.is_empty() {
272             return None;
273         }
274         Some(builder)
275     }
276 
277     /// Splits the `Uri` into its parts.
278     ///
279     /// # Examples
280     ///
281     /// ```
282     /// use ylong_http::request::uri::{Scheme, Uri};
283     ///
284     /// let uri = Uri::from_bytes(b"http://example.com:80/foo?a=1").unwrap();
285     /// let (scheme, auth, path, query) = uri.into_parts();
286     /// assert_eq!(scheme, Some(Scheme::HTTP));
287     /// assert_eq!(auth.unwrap().to_string(), String::from("example.com:80"));
288     /// assert_eq!(path.unwrap().as_str(), "/foo");
289     /// assert_eq!(query.unwrap().as_str(), "a=1");
290     /// ```
291     #[rustfmt::skip] // rust fmt check will add "," after `self`
into_parts( self ) -> ( Option<Scheme>, Option<Authority>, Option<Path>, Option<Query>, )292     pub fn into_parts(
293         self
294     ) -> (
295         Option<Scheme>,
296         Option<Authority>,
297         Option<Path>,
298         Option<Query>,
299     ) {
300         (self.scheme, self.authority, self.path, self.query)
301     }
302 
303     /// Creates an `Uri` from `Scheme`, `Authority`, `Path`, `Query`.
304     ///
305     /// # Examples
306     ///
307     /// ```
308     /// use ylong_http::request::uri::Uri;
309     ///
310     /// let uri = Uri::from_raw_parts(None, None, None, None);
311     /// ```
from_raw_parts( scheme: Option<Scheme>, authority: Option<Authority>, path: Option<Path>, query: Option<Query>, ) -> Self312     pub fn from_raw_parts(
313         scheme: Option<Scheme>,
314         authority: Option<Authority>,
315         path: Option<Path>,
316         query: Option<Query>,
317     ) -> Self {
318         Self {
319             scheme,
320             authority,
321             path,
322             query,
323         }
324     }
325 }
326 
327 impl ToString for Uri {
to_string(&self) -> String328     fn to_string(&self) -> String {
329         let mut builder = String::new();
330         if let Some(scheme) = self.scheme() {
331             builder.push_str(scheme.as_str());
332             builder.push_str("://");
333         }
334         if let Some(host) = self.host() {
335             builder.push_str(host.as_str());
336         }
337         if let Some(port) = self.port() {
338             builder.push(':');
339             builder.push_str(port.as_str());
340         }
341         if let Some(path) = self.path() {
342             builder.push_str(path.as_str());
343         }
344         if let Some(query) = self.query() {
345             builder.push('?');
346             builder.push_str(query.as_str());
347         }
348         builder
349     }
350 }
351 
352 impl<'a> TryFrom<&'a [u8]> for Uri {
353     type Error = HttpError;
354 
try_from(s: &'a [u8]) -> Result<Self, Self::Error>355     fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
356         Self::from_bytes(s)
357     }
358 }
359 
360 impl<'a> TryFrom<&'a str> for Uri {
361     type Error = HttpError;
362 
try_from(s: &'a str) -> Result<Self, Self::Error>363     fn try_from(s: &'a str) -> Result<Self, Self::Error> {
364         Self::from_bytes(s.as_bytes())
365     }
366 }
367 
368 /// A builder of `Uri`, which you can use it to construct a [`Uri`].
369 ///
370 /// [`Uri`]: Uri
371 ///
372 /// # Example
373 ///
374 /// ```
375 /// use ylong_http::request::uri::Uri;
376 ///
377 /// let uri = Uri::builder()
378 ///     .scheme("http")
379 ///     .authority("example.com:80")
380 ///     .path("/foo")
381 ///     .query("a=1")
382 ///     .build()
383 ///     .unwrap();
384 /// ```
385 pub struct UriBuilder {
386     unprocessed: Result<Uri, InvalidUri>,
387 }
388 
389 impl UriBuilder {
390     /// Creates a new, default `UriBuilder`.
391     ///
392     /// # Examples
393     ///
394     /// ```
395     /// use ylong_http::request::uri::UriBuilder;
396     ///
397     /// let uri = UriBuilder::new();
398     /// ```
new() -> Self399     pub fn new() -> Self {
400         UriBuilder::default()
401     }
402 
403     /// Sets the `Scheme` of `Uri`.
404     ///
405     /// # Examples
406     ///
407     /// ```
408     /// use ylong_http::request::uri::UriBuilder;
409     ///
410     /// // This method takes a generic parameter that supports multiple types.
411     /// let builder = UriBuilder::new().scheme("http");
412     /// let builder = UriBuilder::new().scheme("http".as_bytes());
413     /// ```
scheme<T>(mut self, scheme: T) -> Self where Scheme: TryFrom<T>, InvalidUri: From<<Scheme as TryFrom<T>>::Error>,414     pub fn scheme<T>(mut self, scheme: T) -> Self
415     where
416         Scheme: TryFrom<T>,
417         InvalidUri: From<<Scheme as TryFrom<T>>::Error>,
418     {
419         self.unprocessed = self.unprocessed.and_then(move |mut unprocessed| {
420             let scheme = scheme.try_into()?;
421             unprocessed.scheme = Some(scheme);
422             Ok(unprocessed)
423         });
424         self
425     }
426 
427     /// Sets the `Authority` of `Uri`.
428     ///
429     /// # Examples
430     ///
431     /// ```
432     /// use ylong_http::request::uri::UriBuilder;
433     ///
434     /// // This method takes a generic parameter that supports multiple types.
435     /// let builder = UriBuilder::new().authority("example.com:80");
436     /// let builder = UriBuilder::new().authority("example.com:80".as_bytes());
437     /// ```
authority<T>(mut self, auth: T) -> Self where Authority: TryFrom<T>, InvalidUri: From<<Authority as TryFrom<T>>::Error>,438     pub fn authority<T>(mut self, auth: T) -> Self
439     where
440         Authority: TryFrom<T>,
441         InvalidUri: From<<Authority as TryFrom<T>>::Error>,
442     {
443         self.unprocessed = self.unprocessed.and_then(move |mut unprocessed| {
444             let auth = auth.try_into()?;
445             unprocessed.authority = Some(auth);
446             Ok(unprocessed)
447         });
448         self
449     }
450 
451     /// Sets the `Path` of `Uri`.
452     ///
453     /// # Examples
454     ///
455     /// ```
456     /// use ylong_http::request::uri::UriBuilder;
457     ///
458     /// let mut builder = UriBuilder::new().path("/foo");
459     /// let mut builder = UriBuilder::new().path("/foo".as_bytes());
460     /// ```
path<T>(mut self, path: T) -> Self where Path: TryFrom<T>, InvalidUri: From<<Path as TryFrom<T>>::Error>,461     pub fn path<T>(mut self, path: T) -> Self
462     where
463         Path: TryFrom<T>,
464         InvalidUri: From<<Path as TryFrom<T>>::Error>,
465     {
466         self.unprocessed = self.unprocessed.and_then(move |mut unprocessed| {
467             let path = path.try_into()?;
468             unprocessed.path = Some(path);
469             Ok(unprocessed)
470         });
471         self
472     }
473 
474     /// Sets the `Query` of `Uri`.
475     ///
476     /// # Examples
477     ///
478     /// ```
479     /// use ylong_http::request::uri::UriBuilder;
480     ///
481     /// let builder = UriBuilder::new().query("a=1");
482     /// let builder = UriBuilder::new().query("a=1".as_bytes());
483     /// ```
query<T>(mut self, query: T) -> Self where Query: TryFrom<T>, InvalidUri: From<<Query as TryFrom<T>>::Error>,484     pub fn query<T>(mut self, query: T) -> Self
485     where
486         Query: TryFrom<T>,
487         InvalidUri: From<<Query as TryFrom<T>>::Error>,
488     {
489         self.unprocessed = self.unprocessed.and_then(move |mut unprocessed| {
490             let query = query.try_into()?;
491             unprocessed.query = Some(query);
492             Ok(unprocessed)
493         });
494         self
495     }
496 
497     /// Consumes the builder and constructs a valid `Uri`.
498     ///
499     /// # Examples
500     ///
501     /// ```
502     /// use ylong_http::request::uri::UriBuilder;
503     ///
504     /// let uri = UriBuilder::new()
505     ///     .scheme("http")
506     ///     .authority("example.com:80")
507     ///     .path("/foo")
508     ///     .query("a=1")
509     ///     .build()
510     ///     .unwrap();
511     /// ```
build(self) -> Result<Uri, HttpError>512     pub fn build(self) -> Result<Uri, HttpError> {
513         self.unprocessed
514             .and_then(validity_check)
515             .map_err(Into::into)
516     }
517 }
518 
519 impl Default for UriBuilder {
default() -> UriBuilder520     fn default() -> UriBuilder {
521         UriBuilder {
522             unprocessed: Ok(Uri {
523                 scheme: None,
524                 authority: None,
525                 path: None,
526                 query: None,
527             }),
528         }
529     }
530 }
531 
532 /// Scheme component of [`Uri`].
533 ///
534 /// [`Uri`]: Uri
535 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
536 pub struct Scheme {
537     proto: Protocol,
538 }
539 
540 impl Scheme {
541     /// HTTP protocol Scheme.
542     pub const HTTP: Scheme = Scheme {
543         proto: Protocol::Http,
544     };
545 
546     /// HTTPS protocol Scheme.
547     pub const HTTPS: Scheme = Scheme {
548         proto: Protocol::Https,
549     };
550 
551     /// Converts a byte slice into a `Scheme`.
552     ///
553     /// This method only accepts `b"http"` and `b"https"` as input.
554     ///
555     /// # Examples
556     ///
557     /// ```
558     /// use ylong_http::request::uri::Scheme;
559     ///
560     /// let scheme = Scheme::from_bytes(b"http").unwrap();
561     /// ```
from_bytes(bytes: &[u8]) -> Result<Scheme, InvalidUri>562     pub fn from_bytes(bytes: &[u8]) -> Result<Scheme, InvalidUri> {
563         if bytes.eq_ignore_ascii_case(b"http") {
564             Ok(Protocol::Http.into())
565         } else if bytes.eq_ignore_ascii_case(b"https") {
566             Ok(Protocol::Https.into())
567         } else {
568             Err(InvalidUri::InvalidScheme)
569         }
570     }
571 
572     /// Returns a string slice containing the entire `Scheme`.
573     ///
574     /// # Examples
575     ///
576     /// ```
577     /// use ylong_http::request::uri::Scheme;
578     ///
579     /// let scheme = Scheme::from_bytes(b"http").unwrap();
580     /// assert_eq!(scheme.as_str(), "http");
581     /// ```
as_str(&self) -> &str582     pub fn as_str(&self) -> &str {
583         match &self.proto {
584             Protocol::Http => "http",
585             Protocol::Https => "https",
586         }
587     }
588 
589     /// Returns the default port of current uri `Scheme`.
590     ///
591     /// # Example
592     ///
593     /// ```
594     /// use ylong_http::request::uri::Scheme;
595     ///
596     /// let scheme = Scheme::from_bytes(b"http").unwrap();
597     /// assert_eq!(scheme.default_port(), 80);
598     /// ```
default_port(&self) -> u16599     pub fn default_port(&self) -> u16 {
600         match *self {
601             Scheme::HTTP => 80,
602             Scheme::HTTPS => 443,
603         }
604     }
605 }
606 
607 impl From<Protocol> for Scheme {
from(proto: Protocol) -> Self608     fn from(proto: Protocol) -> Self {
609         Scheme { proto }
610     }
611 }
612 
613 impl<'a> TryFrom<&'a [u8]> for Scheme {
614     type Error = InvalidUri;
615 
try_from(bytes: &'a [u8]) -> Result<Self, Self::Error>616     fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
617         Scheme::from_bytes(bytes)
618     }
619 }
620 
621 impl<'a> TryFrom<&'a str> for Scheme {
622     type Error = InvalidUri;
623 
try_from(s: &'a str) -> Result<Self, Self::Error>624     fn try_from(s: &'a str) -> Result<Self, Self::Error> {
625         TryFrom::try_from(s.as_bytes())
626     }
627 }
628 
629 /// Authority component of [`Uri`].
630 ///
631 /// [`Uri`]: Uri
632 #[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
633 pub struct Authority {
634     host: Host,
635     port: Option<Port>,
636 }
637 
638 impl Authority {
639     /// Converts a byte slice into a `Authority`.
640     ///
641     /// # Examples
642     ///
643     /// ```
644     /// use ylong_http::request::uri::Authority;
645     ///
646     /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
647     /// ```
from_bytes(bytes: &[u8]) -> Result<Authority, InvalidUri>648     pub fn from_bytes(bytes: &[u8]) -> Result<Authority, InvalidUri> {
649         if bytes.is_empty() {
650             return Err(InvalidUri::UriMissAuthority);
651         }
652         let (authority, rest) = authority_token(bytes)?;
653         if rest.is_empty() {
654             if let Some(auth) = authority {
655                 return Ok(auth);
656             }
657         }
658         Err(InvalidUri::InvalidAuthority)
659     }
660 
661     /// Gets an immutable reference to `Host`.
662     ///
663     /// # Examples
664     ///
665     /// ```
666     /// use ylong_http::request::uri::{Authority, Host};
667     ///
668     /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
669     /// let host = authority.host();
670     /// assert_eq!(host.as_str(), "example.com");
671     /// ```
host(&self) -> &Host672     pub fn host(&self) -> &Host {
673         &self.host
674     }
675 
676     /// Gets a immutable reference to `Port`.
677     ///
678     /// # Examples
679     ///
680     /// ```
681     /// use ylong_http::request::uri::{Authority, Port};
682     ///
683     /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
684     /// let port = authority.port().unwrap();
685     /// assert_eq!(port.as_str(), "80");
686     /// ```
port(&self) -> Option<&Port>687     pub fn port(&self) -> Option<&Port> {
688         self.port.as_ref()
689     }
690 
691     /// Returns a string containing the entire `Authority`.
692     ///
693     /// # Examples
694     ///
695     /// ```
696     /// use ylong_http::request::uri::{Authority, Port};
697     ///
698     /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
699     /// assert_eq!(authority.to_str(), "example.com:80".to_string());
700     /// ```
to_str(&self) -> String701     pub fn to_str(&self) -> String {
702         let mut auth = self.host.as_str().to_string();
703         if let Some(ref p) = self.port {
704             auth.push(':');
705             auth.push_str(p.as_str());
706         };
707         auth
708     }
709 
710     /// Splits the `Authority` into its parts.
711     ///
712     /// # Examples
713     ///
714     /// ```
715     /// use ylong_http::request::uri::Authority;
716     ///
717     /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
718     /// let (host, port) = authority.into_parts();
719     /// assert_eq!(host.as_str(), "example.com");
720     /// assert_eq!(port.unwrap().as_u16().unwrap(), 80);
721     /// ```
into_parts(self) -> (Host, Option<Port>)722     pub fn into_parts(self) -> (Host, Option<Port>) {
723         (self.host, self.port)
724     }
725 }
726 
727 impl<'a> TryFrom<&'a [u8]> for Authority {
728     type Error = InvalidUri;
729 
try_from(bytes: &'a [u8]) -> Result<Self, Self::Error>730     fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
731         Authority::from_bytes(bytes)
732     }
733 }
734 
735 impl<'a> TryFrom<&'a str> for Authority {
736     type Error = InvalidUri;
737 
try_from(s: &'a str) -> Result<Self, Self::Error>738     fn try_from(s: &'a str) -> Result<Self, Self::Error> {
739         TryFrom::try_from(s.as_bytes())
740     }
741 }
742 
743 impl ToString for Authority {
to_string(&self) -> String744     fn to_string(&self) -> String {
745         let mut builder = String::new();
746         builder.push_str(self.host().as_str());
747         if let Some(port) = self.port() {
748             builder.push(':');
749             builder.push_str(port.as_str());
750         }
751         builder
752     }
753 }
754 
755 /// Host part of [`Authority`].
756 ///
757 /// [`Authority`]: Authority
758 #[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
759 pub struct Host(String);
760 
761 impl Host {
762     /// Returns a string slice containing the entire `Host`.
763     ///
764     /// # Examples
765     ///
766     /// ```
767     /// use ylong_http::request::uri::Authority;
768     ///
769     /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
770     /// let host = authority.host();
771     /// assert_eq!(host.as_str(), "example.com");
772     /// ```
as_str(&self) -> &str773     pub fn as_str(&self) -> &str {
774         self.0.as_str()
775     }
776 }
777 
778 impl ToString for Host {
to_string(&self) -> String779     fn to_string(&self) -> String {
780         self.0.to_owned()
781     }
782 }
783 
784 /// Port part of [`Authority`].
785 ///
786 /// [`Authority`]: Authority
787 #[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
788 pub struct Port(String);
789 
790 impl Port {
791     /// Returns a string slice containing the entire `Port`.
792     ///
793     /// # Examples
794     ///
795     /// ```
796     /// use ylong_http::request::uri::{Authority, Port};
797     ///
798     /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
799     /// let port = authority.port().unwrap();
800     /// assert_eq!(port.as_str(), "80");
801     /// ```
as_str(&self) -> &str802     pub fn as_str(&self) -> &str {
803         self.0.as_str()
804     }
805 
806     /// Returns a u16 value of the `Port`.
807     ///
808     /// # Examples
809     ///
810     /// ```
811     /// use ylong_http::request::uri::{Authority, Port};
812     ///
813     /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
814     /// let port = authority.port().unwrap();
815     /// assert_eq!(port.as_u16().unwrap(), 80);
816     /// ```
as_u16(&self) -> Result<u16, HttpError>817     pub fn as_u16(&self) -> Result<u16, HttpError> {
818         self.0
819             .parse::<u16>()
820             .map_err(|_| ErrorKind::Uri(InvalidUri::InvalidPort).into())
821     }
822 }
823 
824 /// Path component of [`Uri`].
825 ///
826 /// [`Uri`]: Uri
827 #[derive(Clone, Debug, Default)]
828 pub struct Path(String);
829 
830 impl Path {
831     /// Converts a byte slice into a `Path`.
832     ///
833     /// # Examples
834     ///
835     /// ```
836     /// use ylong_http::request::uri::Path;
837     ///
838     /// let path = Path::from_bytes(b"/foo").unwrap();
839     /// assert_eq!(path.as_str(), "/foo");
840     /// ```
from_bytes(bytes: &[u8]) -> Result<Path, InvalidUri>841     pub fn from_bytes(bytes: &[u8]) -> Result<Path, InvalidUri> {
842         let (path, rest) = path_token(bytes)?;
843         if rest.is_empty() {
844             path.ok_or(InvalidUri::UriMissPath)
845         } else {
846             Err(InvalidUri::InvalidPath)
847         }
848     }
849 
850     /// Returns a string slice containing the entire `Path`.
851     ///
852     /// # Examples
853     ///
854     /// ```
855     /// use ylong_http::request::uri::Path;
856     ///
857     /// let path = Path::from_bytes(b"/foo").unwrap();
858     /// assert_eq!(path.as_str(), "/foo");
859     /// ```
as_str(&self) -> &str860     pub fn as_str(&self) -> &str {
861         self.0.as_str()
862     }
863 }
864 
865 impl<'a> TryFrom<&'a [u8]> for Path {
866     type Error = InvalidUri;
867 
try_from(bytes: &'a [u8]) -> Result<Self, Self::Error>868     fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
869         Path::from_bytes(bytes)
870     }
871 }
872 
873 impl<'a> TryFrom<&'a str> for Path {
874     type Error = InvalidUri;
875 
try_from(s: &'a str) -> Result<Self, Self::Error>876     fn try_from(s: &'a str) -> Result<Self, Self::Error> {
877         TryFrom::try_from(s.as_bytes())
878     }
879 }
880 
881 /// Query component of [`Uri`].
882 ///
883 /// [`Uri`]: Uri
884 #[derive(Clone, Debug, Default)]
885 pub struct Query(String);
886 
887 impl Query {
888     /// Converts a byte slice into a `Query`.
889     ///
890     /// # Examples
891     ///
892     /// ```
893     /// use ylong_http::request::uri::Query;
894     ///
895     /// let query = Query::from_bytes(b"a=1").unwrap();
896     /// assert_eq!(query.as_str(), "a=1");
897     /// ```
from_bytes(bytes: &[u8]) -> Result<Query, InvalidUri>898     pub fn from_bytes(bytes: &[u8]) -> Result<Query, InvalidUri> {
899         let query = query_token(bytes)?;
900         query.ok_or(InvalidUri::UriMissQuery)
901     }
902 
903     /// Returns a string slice containing the entire `Query`.
904     ///
905     /// # Examples
906     ///
907     /// ```
908     /// use ylong_http::request::uri::Query;
909     ///
910     /// let query = Query::from_bytes(b"a=1").unwrap();
911     /// assert_eq!(query.as_str(), "a=1");
912     /// ```
as_str(&self) -> &str913     pub fn as_str(&self) -> &str {
914         self.0.as_str()
915     }
916 }
917 
918 impl<'a> TryFrom<&'a [u8]> for Query {
919     type Error = InvalidUri;
920 
try_from(s: &'a [u8]) -> Result<Self, Self::Error>921     fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
922         Query::from_bytes(s)
923     }
924 }
925 
926 impl<'a> TryFrom<&'a str> for Query {
927     type Error = InvalidUri;
928 
try_from(s: &'a str) -> Result<Self, Self::Error>929     fn try_from(s: &'a str) -> Result<Self, Self::Error> {
930         TryFrom::try_from(s.as_bytes())
931     }
932 }
933 
934 /// `Protocol` indicates the scheme type supported by [`Uri`].
935 ///
936 /// [`Uri`]: Uri
937 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
938 enum Protocol {
939     Http,
940     Https,
941 }
942 
943 /// Error types generated during [`Uri`] construction due to different causes.
944 ///
945 /// [`Uri`]: Uri
946 #[derive(Debug, Eq, PartialEq)]
947 pub enum InvalidUri {
948     /// Invalid scheme
949     InvalidScheme,
950     /// Invalid authority
951     InvalidAuthority,
952     /// Invalid path
953     InvalidPath,
954     /// Invalid byte
955     InvalidByte,
956     /// Invalid format
957     InvalidFormat,
958     /// Invalid port
959     InvalidPort,
960     /// Missing scheme
961     UriMissScheme,
962     /// Missing path
963     UriMissPath,
964     /// Missing query
965     UriMissQuery,
966     /// Missing authority
967     UriMissAuthority,
968     /// Missing host
969     UriMissHost,
970     /// Contains Userinfo
971     UriContainUserinfo,
972     /// Too long
973     UriTooLong,
974 }
975 
976 impl From<Infallible> for InvalidUri {
from(_: Infallible) -> Self977     fn from(_: Infallible) -> Self {
978         unimplemented!()
979     }
980 }
981 
bytes_to_str(bytes: &[u8]) -> &str982 fn bytes_to_str(bytes: &[u8]) -> &str {
983     unsafe { std::str::from_utf8_unchecked(bytes) }
984 }
985 
scheme_token(bytes: &[u8]) -> Result<(Option<Scheme>, &[u8]), InvalidUri>986 fn scheme_token(bytes: &[u8]) -> Result<(Option<Scheme>, &[u8]), InvalidUri> {
987     const HTTP_SCHEME_LENGTH: usize = "http://".len();
988     const HTTPS_SCHEME_LENGTH: usize = "https://".len();
989     // Obtains the position of colons that separate schemes.
990     let pos = match bytes.iter().enumerate().find(|(_, &b)| b == b':') {
991         Some((index, _))
992             if index != 0
993                 && bytes[index..].len() > 2
994                 && bytes[index + 1..index + 3].eq_ignore_ascii_case(b"//") =>
995         {
996             index
997         }
998         Some((0, _)) => return Err(InvalidUri::InvalidScheme),
999         _ => return Ok((None, bytes)),
1000     };
1001     // Currently, only HTTP and HTTPS are supported. Therefore, you need to verify
1002     // the scheme content.
1003     if bytes[..pos].eq_ignore_ascii_case(b"http") {
1004         Ok((Some(Protocol::Http.into()), &bytes[HTTP_SCHEME_LENGTH..]))
1005     } else if bytes[..pos].eq_ignore_ascii_case(b"https") {
1006         Ok((Some(Protocol::Https.into()), &bytes[HTTPS_SCHEME_LENGTH..]))
1007     } else {
1008         Err(InvalidUri::InvalidScheme)
1009     }
1010 }
1011 
authority_token(bytes: &[u8]) -> Result<(Option<Authority>, &[u8]), InvalidUri>1012 fn authority_token(bytes: &[u8]) -> Result<(Option<Authority>, &[u8]), InvalidUri> {
1013     let mut end = bytes.len();
1014     let mut colon_num = 0;
1015     let mut left_bracket = false;
1016     let mut right_bracket = false;
1017     for (i, &b) in bytes.iter().enumerate() {
1018         match b {
1019             b'/' | b'?' | b'#' => {
1020                 end = i;
1021                 break;
1022             }
1023             b'[' => {
1024                 if i == 0 {
1025                     left_bracket = true;
1026                 } else if left_bracket {
1027                     return Err(InvalidUri::InvalidAuthority);
1028                 }
1029             }
1030             b']' => {
1031                 if left_bracket {
1032                     if right_bracket {
1033                         return Err(InvalidUri::InvalidAuthority);
1034                     } else {
1035                         right_bracket = true;
1036                         // The ':' between '[' and ']' is in ipv6 and should be ignored.
1037                         colon_num = 0;
1038                     }
1039                 }
1040             }
1041             // TODO According to RFC3986, the character @ can be one of the reserved characters,
1042             // which needs to be improved after being familiar with the rules.
1043             b'@' => {
1044                 return Err(InvalidUri::UriContainUserinfo);
1045             }
1046             b':' => {
1047                 colon_num += 1;
1048             }
1049             other => {
1050                 if !URI_VALUE_BYTES[other as usize] {
1051                     return Err(InvalidUri::InvalidByte);
1052                 }
1053             }
1054         }
1055     }
1056     authority_parse(bytes, end, colon_num, left_bracket, right_bracket)
1057 }
1058 
authority_parse( bytes: &[u8], end: usize, colon_num: i32, left_bracket: bool, right_bracket: bool, ) -> Result<(Option<Authority>, &[u8]), InvalidUri>1059 fn authority_parse(
1060     bytes: &[u8],
1061     end: usize,
1062     colon_num: i32,
1063     left_bracket: bool,
1064     right_bracket: bool,
1065 ) -> Result<(Option<Authority>, &[u8]), InvalidUri> {
1066     // The authority does not exist.
1067     if end == 0 {
1068         return Ok((None, &bytes[end..]));
1069     }
1070 
1071     // Incomplete square brackets
1072     if left_bracket ^ right_bracket {
1073         return Err(InvalidUri::InvalidAuthority);
1074     }
1075     // There are multiple colons in addition to IPv6.
1076     if colon_num > 1 {
1077         return Err(InvalidUri::InvalidAuthority);
1078     }
1079     let authority = host_port(&bytes[..end], colon_num)?;
1080     Ok((Some(authority), &bytes[end..]))
1081 }
1082 
path_token(bytes: &[u8]) -> Result<(Option<Path>, &[u8]), InvalidUri>1083 fn path_token(bytes: &[u8]) -> Result<(Option<Path>, &[u8]), InvalidUri> {
1084     let mut end = bytes.len();
1085     for (i, &b) in bytes.iter().enumerate() {
1086         match b {
1087             b'?' | b'#' => {
1088                 end = i;
1089                 break;
1090             }
1091             _ => {
1092                 // "{} The three characters that might be used were previously percent-encoding.
1093                 if !PATH_AND_QUERY_BYTES[b as usize] {
1094                     return Err(InvalidUri::InvalidByte);
1095                 }
1096             }
1097         }
1098     }
1099     if end != 0 {
1100         let path = bytes_to_str(&bytes[..end]).to_string();
1101         Ok((Some(Path(path)), &bytes[end..]))
1102     } else {
1103         Ok((None, &bytes[end..]))
1104     }
1105 }
1106 
query_token(bytes: &[u8]) -> Result<Option<Query>, InvalidUri>1107 fn query_token(bytes: &[u8]) -> Result<Option<Query>, InvalidUri> {
1108     if bytes.is_empty() {
1109         return Ok(None);
1110     }
1111     let mut end = bytes.len();
1112     for (i, &b) in bytes.iter().enumerate() {
1113         match b {
1114             b'#' => {
1115                 end = i;
1116                 break;
1117             }
1118             // ?|  ` |  { |  }
1119             0x3F | 0x60 | 0x7B | 0x7D => {}
1120             _ => {
1121                 if !PATH_AND_QUERY_BYTES[b as usize] {
1122                     return Err(InvalidUri::InvalidByte);
1123                 }
1124             }
1125         }
1126     }
1127     if end == 0 {
1128         return Ok(None);
1129     }
1130     let query = bytes_to_str(&bytes[..end]);
1131     Ok(Some(Query(query.to_string())))
1132 }
1133 
host_port(auth: &[u8], colon_num: i32) -> Result<Authority, InvalidUri>1134 fn host_port(auth: &[u8], colon_num: i32) -> Result<Authority, InvalidUri> {
1135     let authority = bytes_to_str(auth);
1136     if colon_num != 0 {
1137         match authority.rsplit_once(':') {
1138             Some((host, port)) => {
1139                 if host.is_empty() {
1140                     Err(InvalidUri::UriMissHost)
1141                 } else if port.is_empty() {
1142                     Ok(Authority {
1143                         host: Host(host.to_string()),
1144                         port: None,
1145                     })
1146                 } else {
1147                     port.parse::<u16>().map_err(|_| InvalidUri::InvalidPort)?;
1148                     Ok(Authority {
1149                         host: Host(host.to_string()),
1150                         port: Some(Port(port.to_string())),
1151                     })
1152                 }
1153             }
1154             None => Err(InvalidUri::UriMissAuthority),
1155         }
1156     } else {
1157         Ok(Authority {
1158             host: Host(authority.to_string()),
1159             port: None,
1160         })
1161     }
1162 }
1163 
validity_check(unchecked_uri: Uri) -> Result<Uri, InvalidUri>1164 fn validity_check(unchecked_uri: Uri) -> Result<Uri, InvalidUri> {
1165     match (
1166         &unchecked_uri.scheme,
1167         &unchecked_uri.authority,
1168         &unchecked_uri.path,
1169         &unchecked_uri.query,
1170     ) {
1171         (Some(_), None, _, _) => Err(InvalidUri::UriMissAuthority),
1172         (None, Some(_), Some(_), _) => Err(InvalidUri::UriMissScheme),
1173         (None, Some(_), _, Some(_)) => Err(InvalidUri::UriMissScheme),
1174         (None, None, None, None) => Err(InvalidUri::InvalidFormat),
1175         _ => Ok(unchecked_uri),
1176     }
1177 }
1178 
1179 #[rustfmt::skip]
1180 const URI_VALUE_BYTES: [bool; 256] = {
1181     const __: bool = false;
1182     const TT: bool = true;
1183     [
1184 //      \0                                  HT  LF          CR
1185         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F
1186         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 1F
1187 //      \w  !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
1188         __, TT, __, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 2F
1189 //      0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
1190         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, __, TT, __, TT, // 3F
1191 //      @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
1192         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 4F
1193 //      P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _
1194         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, __, TT, __, TT, // 5F
1195 //      `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
1196         __, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 6F
1197 //      p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~   del
1198         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, __, __, __, TT, __, // 7F
1199 //      Expand ascii
1200         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8F
1201         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9F
1202         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // AF
1203         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // BF
1204         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // CF
1205         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // DF
1206         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // EF
1207         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // FF
1208     ]
1209 };
1210 
1211 #[rustfmt::skip]
1212 const PATH_AND_QUERY_BYTES: [bool; 256] = {
1213     const __: bool = false;
1214     const TT: bool = true;
1215     [
1216 //      \0                                  HT  LF          CR
1217         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F
1218         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 1F
1219 //      \w  !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
1220         __, TT, __, __, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 2F
1221 //      0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
1222         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, __, TT, __, __, // 3F
1223 //      @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
1224         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 4F
1225 //      P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _
1226         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 5F
1227 //      `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
1228         __, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 6F
1229 //      p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~   del
1230         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, __, TT, __, TT, __, // 7F
1231 //      Expand ascii
1232         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8F
1233         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9F
1234         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // AF
1235         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // BF
1236         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // CF
1237         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // DF
1238         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // EF
1239         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // FF
1240     ]
1241 };
1242 
1243 #[cfg(test)]
1244 mod ut_uri {
1245     use super::{InvalidUri, Scheme, Uri, UriBuilder};
1246     use crate::error::{ErrorKind, HttpError};
1247 
1248     macro_rules! test_builder_valid {
1249         ($res1:expr, $res2:expr) => {{
1250             let uri = UriBuilder::new()
1251                 .scheme($res1.0)
1252                 .authority($res1.1)
1253                 .path($res1.2)
1254                 .query($res1.3)
1255                 .build()
1256                 .unwrap();
1257             assert_eq!(uri.scheme().unwrap().as_str(), $res2.0);
1258             assert_eq!(uri.host().unwrap().as_str(), $res2.1);
1259             assert_eq!(uri.port().unwrap().as_str(), $res2.2);
1260             assert_eq!(uri.path().unwrap().as_str(), $res2.3);
1261             assert_eq!(uri.query().unwrap().as_str(), $res2.4);
1262             assert_eq!(uri.to_string(), $res2.5)
1263         }};
1264     }
1265 
1266     /// UT test cases for `build_from_builder`.
1267     ///
1268     /// # Brief
1269     /// 1. Creates UriBuilder by calling UriBuilder::new().
1270     /// 2. Sets Scheme by calling scheme().
1271     /// 3. Sets authority by calling authority().
1272     /// 4. Sets path by calling path().
1273     /// 5. Sets query by calling query().
1274     /// 6. Creates Uri by calling build().
1275     /// 7. Gets string slice value of uri components by calling as_str().
1276     /// 8. Gets string value of uri by calling to_string().
1277     /// 9. Checks if the test result is correct by assert_eq!().
1278     #[test]
build_from_builder()1279     fn build_from_builder() {
1280         test_builder_valid!(
1281             ("http", "hyper.rs:80", "/foo", "a=1"),
1282             (
1283                 "http",
1284                 "hyper.rs",
1285                 "80",
1286                 "/foo",
1287                 "a=1",
1288                 "http://hyper.rs:80/foo?a=1"
1289             )
1290         );
1291         test_builder_valid!(
1292             (Scheme::HTTP, "hyper.rs:80", "/foo", "a=1"),
1293             (
1294                 "http",
1295                 "hyper.rs",
1296                 "80",
1297                 "/foo",
1298                 "a=1",
1299                 "http://hyper.rs:80/foo?a=1"
1300             )
1301         );
1302         test_builder_valid!(
1303             ("https", "hyper.rs:80", "/foo", "a=1"),
1304             (
1305                 "https",
1306                 "hyper.rs",
1307                 "80",
1308                 "/foo",
1309                 "a=1",
1310                 "https://hyper.rs:80/foo?a=1"
1311             )
1312         );
1313         test_builder_valid!(
1314             (Scheme::HTTPS, "hyper.rs:80", "/foo", "a=1"),
1315             (
1316                 "https",
1317                 "hyper.rs",
1318                 "80",
1319                 "/foo",
1320                 "a=1",
1321                 "https://hyper.rs:80/foo?a=1"
1322             )
1323         );
1324     }
1325 
1326     /// UT test cases for `build_from_instance`.
1327     ///
1328     /// # Brief
1329     /// 1. Creates UriBuilder by calling Uri::builder().
1330     /// 2. Sets Scheme by calling scheme().
1331     /// 3. Sets authority by calling authority().
1332     /// 4. Sets path by calling path().
1333     /// 5. Sets query by calling query().
1334     /// 6. Creates Uri by calling build().
1335     /// 7. Gets string slice value of uri components by calling as_str().
1336     /// 8. Gets string value of uri by calling to_string().
1337     /// 9. Checks if the test result is correct by assert_eq!().
1338     #[test]
build_from_instance()1339     fn build_from_instance() {
1340         let uri = Uri::builder()
1341             .scheme(Scheme::HTTP)
1342             .authority("hyper.rs:80")
1343             .path("/foo")
1344             .query("a=1")
1345             .build()
1346             .unwrap();
1347         assert_eq!(uri.scheme().unwrap().as_str(), "http");
1348         assert_eq!(uri.host().unwrap().as_str(), "hyper.rs");
1349         assert_eq!(uri.port().unwrap().as_str(), "80");
1350         assert_eq!(uri.path().unwrap().as_str(), "/foo");
1351         assert_eq!(uri.query().unwrap().as_str(), "a=1");
1352         assert_eq!(uri.to_string(), "http://hyper.rs:80/foo?a=1")
1353     }
1354 
1355     /// UT test cases for `build_from_str`.
1356     ///
1357     /// # Brief
1358     /// 1. Creates Uri by calling from_bytes().
1359     /// 2. Gets string slice value of uri components by calling as_str().
1360     /// 3. Gets u16 value of port by call as_u16().
1361     /// 4. Gets string value of uri by calling to_string().
1362     /// 5. Checks if the test result is correct by assert_eq!().
1363     #[test]
build_from_str()1364     fn build_from_str() {
1365         let uri = Uri::from_bytes("http://hyper.rs:80/foo?a=1".as_bytes()).unwrap();
1366         assert_eq!(uri.scheme().unwrap().as_str(), "http");
1367         assert_eq!(uri.host().unwrap().as_str(), "hyper.rs");
1368         assert_eq!(uri.port().unwrap().as_str(), "80");
1369         assert_eq!(uri.port().unwrap().as_u16().unwrap(), 80);
1370         assert_eq!(uri.path().unwrap().as_str(), "/foo");
1371         assert_eq!(uri.query().unwrap().as_str(), "a=1");
1372         assert_eq!(uri.to_string(), "http://hyper.rs:80/foo?a=1")
1373     }
1374 
1375     /// UT test cases for `Scheme::default_port`.
1376     ///
1377     /// # Brief
1378     /// 1. Creates Scheme by calling `Scheme::from_bytes`.
1379     /// 3. Gets u16 value of port by calling `Scheme::default_port`.
1380     /// 5. Checks whether the default port is correct.
1381     #[test]
ut_uri_scheme_default_port()1382     fn ut_uri_scheme_default_port() {
1383         let scheme = Scheme::from_bytes(b"http").unwrap();
1384         assert_eq!(scheme.default_port(), 80);
1385         let scheme = Scheme::from_bytes(b"https").unwrap();
1386         assert_eq!(scheme.default_port(), 443);
1387     }
1388 
1389     /// UT test cases for `Uri::from_bytes`.
1390     ///
1391     /// # Brief
1392     /// 1. Creates Uri by calling `Uri::from_bytes()`.
1393     /// 2. Checks if the test results are correct.
1394     #[test]
ut_uri_from_bytes()1395     fn ut_uri_from_bytes() {
1396         macro_rules! uri_test_case {
1397             ($raw: expr, $tar: expr, $(,)?) => {
1398                 match (Uri::from_bytes($raw), $tar) {
1399                     (Ok(res), Ok(tar)) => assert_eq!(
1400                         (
1401                             res.scheme().map(|scheme| scheme.as_str()),
1402                             res.host().map(|host| host.as_str()),
1403                             res.port().map(|port| port.as_str()),
1404                             res.path().map(|path| path.as_str()),
1405                             res.query().map(|query| query.as_str()),
1406                         ),
1407                         tar,
1408                     ),
1409                     (Err(res), Err(tar)) => assert_eq!(res, tar),
1410                     _ => panic!("uri test case failed!"),
1411                 }
1412             };
1413         }
1414 
1415         uri_test_case!(
1416             b"httpss://www.example.com/",
1417             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidScheme))),
1418         );
1419 
1420         uri_test_case!(
1421             b"://www.example.com/",
1422             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidScheme))),
1423         );
1424 
1425         uri_test_case!(
1426             b"https://www.hu awei.com/",
1427             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1428         );
1429 
1430         uri_test_case!(
1431             br#"https://www.hu"awei.com/"#,
1432             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1433         );
1434 
1435         uri_test_case!(
1436             br#"https://www.hu"awei.com/"#,
1437             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1438         );
1439 
1440         uri_test_case!(
1441             br#"https://www.hu"<>\^`awei.com/"#,
1442             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1443         );
1444 
1445         uri_test_case!(
1446             br#"https://www.example.com:a0/"#,
1447             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidPort))),
1448         );
1449 
1450         uri_test_case!(
1451             br#"https://www.example.com:80/message/e<>mail"#,
1452             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1453         );
1454 
1455         uri_test_case!(
1456             br#"https:/www.example.com:80/message/email?name=arya"#,
1457             Err(HttpError::from(ErrorKind::Uri(InvalidUri::UriMissScheme))),
1458         );
1459 
1460         uri_test_case!(
1461             br#"https:/www.example.com:80"#,
1462             Err(HttpError::from(ErrorKind::Uri(InvalidUri::UriMissScheme))),
1463         );
1464 
1465         uri_test_case!(
1466             br#"https:/www.example.com"#,
1467             Err(HttpError::from(ErrorKind::Uri(InvalidUri::UriMissScheme))),
1468         );
1469 
1470         uri_test_case!(
1471             br#"https://www.huaw:ei.com:80"#,
1472             Err(HttpError::from(ErrorKind::Uri(
1473                 InvalidUri::InvalidAuthority
1474             ))),
1475         );
1476 
1477         uri_test_case!(
1478             br#"https://www.huaw:ei.com:80"#,
1479             Err(HttpError::from(ErrorKind::Uri(
1480                 InvalidUri::InvalidAuthority
1481             ))),
1482         );
1483 
1484         uri_test_case!(
1485             br#"https://name=1234@www.example.com:80/message/email?name=arya"#,
1486             Err(HttpError::from(ErrorKind::Uri(
1487                 InvalidUri::UriContainUserinfo
1488             ))),
1489         );
1490 
1491         uri_test_case!(
1492             br#"www.example.com:80/message/email?name=arya"#,
1493             Err(HttpError::from(ErrorKind::Uri(InvalidUri::UriMissScheme))),
1494         );
1495 
1496         uri_test_case!(
1497             br#"https://[0:0:0:0:0:0:0:0:80/message/email?name=arya"#,
1498             Err(HttpError::from(ErrorKind::Uri(
1499                 InvalidUri::InvalidAuthority
1500             ))),
1501         );
1502 
1503         uri_test_case!(
1504             br#"https:///foo?a=1"#,
1505             Err(HttpError::from(ErrorKind::Uri(
1506                 InvalidUri::UriMissAuthority
1507             ))),
1508         );
1509 
1510         uri_test_case!(
1511             b"https://www.example.com/",
1512             Ok((
1513                 Some("https"),
1514                 Some("www.example.com"),
1515                 None,
1516                 Some("/"),
1517                 None
1518             )),
1519         );
1520 
1521         uri_test_case!(
1522             b"https://www.example.com:80/foo?a=1",
1523             Ok((
1524                 Some("https"),
1525                 Some("www.example.com"),
1526                 Some("80"),
1527                 Some("/foo"),
1528                 Some("a=1"),
1529             )),
1530         );
1531 
1532         uri_test_case!(
1533             b"https://www.example.com:80/foo?a=1#fragment",
1534             Ok((
1535                 Some("https"),
1536                 Some("www.example.com"),
1537                 Some("80"),
1538                 Some("/foo"),
1539                 Some("a=1"),
1540             )),
1541         );
1542 
1543         uri_test_case!(
1544             b"https://www.example.com:80?a=1",
1545             Ok((
1546                 Some("https"),
1547                 Some("www.example.com"),
1548                 Some("80"),
1549                 None,
1550                 Some("a=1"),
1551             )),
1552         );
1553 
1554         uri_test_case!(
1555             b"https://www.example.com?a=1",
1556             Ok((
1557                 Some("https"),
1558                 Some("www.example.com"),
1559                 None,
1560                 None,
1561                 Some("a=1"),
1562             )),
1563         );
1564 
1565         uri_test_case!(
1566             b"https://www.example.com?",
1567             Ok((Some("https"), Some("www.example.com"), None, None, None)),
1568         );
1569 
1570         uri_test_case!(
1571             b"https://www.example.com:80",
1572             Ok((
1573                 Some("https"),
1574                 Some("www.example.com"),
1575                 Some("80"),
1576                 None,
1577                 None,
1578             )),
1579         );
1580 
1581         uri_test_case!(
1582             b"https://www.example.com",
1583             Ok((Some("https"), Some("www.example.com"), None, None, None)),
1584         );
1585 
1586         uri_test_case!(
1587             b"https://www.example.com#fragment",
1588             Ok((Some("https"), Some("www.example.com"), None, None, None)),
1589         );
1590 
1591         uri_test_case!(
1592             b"www.example.com",
1593             Ok((None, Some("www.example.com"), None, None, None)),
1594         );
1595 
1596         uri_test_case!(
1597             b"/foo?a=1",
1598             Ok((None, None, None, Some("/foo"), Some("a=1"))),
1599         );
1600 
1601         uri_test_case!(
1602             b"https://[0:0:0:0:0:0:0:0]",
1603             Ok((Some("https"), Some("[0:0:0:0:0:0:0:0]"), None, None, None)),
1604         );
1605 
1606         uri_test_case!(
1607             b"https://[0:0:0:0:0:0:0:0]:80",
1608             Ok((
1609                 Some("https"),
1610                 Some("[0:0:0:0:0:0:0:0]"),
1611                 Some("80"),
1612                 None,
1613                 None,
1614             )),
1615         );
1616     }
1617 
1618     /// UT test cases for `Uri::authority`.
1619     ///
1620     /// # Brief
1621     /// 1. Creates Uri by calling `Uri::authority()`.
1622     /// 2. Checks if the test results are correct.
1623     #[test]
ut_uri_authority()1624     fn ut_uri_authority() {
1625         let uri = Uri::from_bytes(b"http://example.com:8080/foo?a=1").unwrap();
1626         let authority = uri.authority().unwrap();
1627         assert_eq!(authority.host.as_str(), "example.com");
1628         assert_eq!(authority.port().unwrap().as_str(), "8080");
1629     }
1630 
1631     /// UT test cases for `Uri::path_and_query`.
1632     ///
1633     /// # Brief
1634     /// 1. Creates Uri by calling `Uri::path_and_query()`.
1635     /// 2. Checks if the test results are correct.
1636     #[test]
ut_uri_path_and_query()1637     fn ut_uri_path_and_query() {
1638         let uri = Uri::from_bytes(b"http://example.com:8080/foo?a=1").unwrap();
1639         assert_eq!(uri.path_and_query().unwrap(), "/foo?a=1");
1640 
1641         let uri = Uri::from_bytes(b"http://example.com:8080").unwrap();
1642         assert_eq!(uri.path_and_query(), None);
1643     }
1644 
1645     /// UT test cases for `Uri::path_and_query`.
1646     ///
1647     /// # Brief
1648     /// 1. Creates Uri by calling `Uri::path_and_query()`.
1649     /// 2. Checks that the query containing the {} symbol parses properly.
1650     #[test]
ut_uri_json_query()1651     fn ut_uri_json_query() {
1652         let uri = Uri::from_bytes(b"http://example.com:8080/foo?a=1{WEBO_TEST}").unwrap();
1653         assert_eq!(uri.path_and_query().unwrap(), "/foo?a=1{WEBO_TEST}");
1654     }
1655 }
1656