• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 core::str::FromStr for Host {
779     type Err = HttpError;
780 
781     /// Constructs host from a string slice.
782     ///
783     /// # Examples
784     ///
785     /// ```
786     /// use std::str::FromStr;
787     ///
788     /// use ylong_http::request::uri::Host;
789     ///
790     /// let host = Host::from_str("www.example.com").unwrap();
791     /// assert_eq!(host.as_str(), "www.example.com");
792     /// ```
from_str(host: &str) -> Result<Self, Self::Err>793     fn from_str(host: &str) -> Result<Self, Self::Err> {
794         if host.is_empty() {
795             Err(InvalidUri::UriMissHost.into())
796         } else {
797             Ok(Self(String::from(host)))
798         }
799     }
800 }
801 
802 impl ToString for Host {
to_string(&self) -> String803     fn to_string(&self) -> String {
804         self.0.to_owned()
805     }
806 }
807 
808 /// Port part of [`Authority`].
809 ///
810 /// [`Authority`]: Authority
811 #[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
812 pub struct Port(String);
813 
814 impl Port {
815     /// Returns a string slice containing the entire `Port`.
816     ///
817     /// # Examples
818     ///
819     /// ```
820     /// use ylong_http::request::uri::{Authority, Port};
821     ///
822     /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
823     /// let port = authority.port().unwrap();
824     /// assert_eq!(port.as_str(), "80");
825     /// ```
as_str(&self) -> &str826     pub fn as_str(&self) -> &str {
827         self.0.as_str()
828     }
829 
830     /// Returns an u16 value of the `Port`.
831     ///
832     /// # Examples
833     ///
834     /// ```
835     /// use ylong_http::request::uri::{Authority, Port};
836     ///
837     /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
838     /// let port = authority.port().unwrap();
839     /// assert_eq!(port.as_u16().unwrap(), 80);
840     /// ```
as_u16(&self) -> Result<u16, HttpError>841     pub fn as_u16(&self) -> Result<u16, HttpError> {
842         self.0
843             .parse::<u16>()
844             .map_err(|_| ErrorKind::Uri(InvalidUri::InvalidPort).into())
845     }
846 }
847 
848 impl core::str::FromStr for Port {
849     type Err = HttpError;
850 
851     /// Constructs host from a string slice.
852     ///
853     /// # Examples
854     ///
855     /// ```
856     /// use std::str::FromStr;
857     ///
858     /// use ylong_http::request::uri::Port;
859     ///
860     /// let host = Port::from_str("80").unwrap();
861     /// assert_eq!(host.as_str(), "80");
862     /// ```
from_str(port: &str) -> Result<Self, Self::Err>863     fn from_str(port: &str) -> Result<Self, Self::Err> {
864         port.parse::<u16>().map_err(|_| InvalidUri::InvalidPort)?;
865         Ok(Self(String::from(port)))
866     }
867 }
868 
869 /// Path component of [`Uri`].
870 ///
871 /// [`Uri`]: Uri
872 #[derive(Clone, Debug, Default)]
873 pub struct Path(String);
874 
875 impl Path {
876     /// Converts a byte slice into a `Path`.
877     ///
878     /// # Examples
879     ///
880     /// ```
881     /// use ylong_http::request::uri::Path;
882     ///
883     /// let path = Path::from_bytes(b"/foo").unwrap();
884     /// assert_eq!(path.as_str(), "/foo");
885     /// ```
from_bytes(bytes: &[u8]) -> Result<Path, InvalidUri>886     pub fn from_bytes(bytes: &[u8]) -> Result<Path, InvalidUri> {
887         let (path, rest) = path_token(bytes)?;
888         if rest.is_empty() {
889             path.ok_or(InvalidUri::UriMissPath)
890         } else {
891             Err(InvalidUri::InvalidPath)
892         }
893     }
894 
895     /// Returns a string slice containing the entire `Path`.
896     ///
897     /// # Examples
898     ///
899     /// ```
900     /// use ylong_http::request::uri::Path;
901     ///
902     /// let path = Path::from_bytes(b"/foo").unwrap();
903     /// assert_eq!(path.as_str(), "/foo");
904     /// ```
as_str(&self) -> &str905     pub fn as_str(&self) -> &str {
906         self.0.as_str()
907     }
908 }
909 
910 impl<'a> TryFrom<&'a [u8]> for Path {
911     type Error = InvalidUri;
912 
try_from(bytes: &'a [u8]) -> Result<Self, Self::Error>913     fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
914         Path::from_bytes(bytes)
915     }
916 }
917 
918 impl<'a> TryFrom<&'a str> for Path {
919     type Error = InvalidUri;
920 
try_from(s: &'a str) -> Result<Self, Self::Error>921     fn try_from(s: &'a str) -> Result<Self, Self::Error> {
922         TryFrom::try_from(s.as_bytes())
923     }
924 }
925 
926 /// Query component of [`Uri`].
927 ///
928 /// [`Uri`]: Uri
929 #[derive(Clone, Debug, Default)]
930 pub struct Query(String);
931 
932 impl Query {
933     /// Converts a byte slice into a `Query`.
934     ///
935     /// # Examples
936     ///
937     /// ```
938     /// use ylong_http::request::uri::Query;
939     ///
940     /// let query = Query::from_bytes(b"a=1").unwrap();
941     /// assert_eq!(query.as_str(), "a=1");
942     /// ```
from_bytes(bytes: &[u8]) -> Result<Query, InvalidUri>943     pub fn from_bytes(bytes: &[u8]) -> Result<Query, InvalidUri> {
944         let query = query_token(bytes)?;
945         query.ok_or(InvalidUri::UriMissQuery)
946     }
947 
948     /// Returns a string slice containing the entire `Query`.
949     ///
950     /// # Examples
951     ///
952     /// ```
953     /// use ylong_http::request::uri::Query;
954     ///
955     /// let query = Query::from_bytes(b"a=1").unwrap();
956     /// assert_eq!(query.as_str(), "a=1");
957     /// ```
as_str(&self) -> &str958     pub fn as_str(&self) -> &str {
959         self.0.as_str()
960     }
961 }
962 
963 impl<'a> TryFrom<&'a [u8]> for Query {
964     type Error = InvalidUri;
965 
try_from(s: &'a [u8]) -> Result<Self, Self::Error>966     fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
967         Query::from_bytes(s)
968     }
969 }
970 
971 impl<'a> TryFrom<&'a str> for Query {
972     type Error = InvalidUri;
973 
try_from(s: &'a str) -> Result<Self, Self::Error>974     fn try_from(s: &'a str) -> Result<Self, Self::Error> {
975         TryFrom::try_from(s.as_bytes())
976     }
977 }
978 
979 /// `Protocol` indicates the scheme type supported by [`Uri`].
980 ///
981 /// [`Uri`]: Uri
982 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
983 enum Protocol {
984     Http,
985     Https,
986 }
987 
988 /// Error types generated during [`Uri`] construction due to different causes.
989 ///
990 /// [`Uri`]: Uri
991 #[derive(Debug, Eq, PartialEq)]
992 pub enum InvalidUri {
993     /// Invalid scheme
994     InvalidScheme,
995     /// Invalid authority
996     InvalidAuthority,
997     /// Invalid path
998     InvalidPath,
999     /// Invalid byte
1000     InvalidByte,
1001     /// Invalid format
1002     InvalidFormat,
1003     /// Invalid port
1004     InvalidPort,
1005     /// Missing scheme
1006     UriMissScheme,
1007     /// Missing path
1008     UriMissPath,
1009     /// Missing query
1010     UriMissQuery,
1011     /// Missing authority
1012     UriMissAuthority,
1013     /// Missing host
1014     UriMissHost,
1015     /// Contains Userinfo
1016     UriContainUserinfo,
1017     /// Too long
1018     UriTooLong,
1019 }
1020 
1021 impl From<Infallible> for InvalidUri {
from(_: Infallible) -> Self1022     fn from(_: Infallible) -> Self {
1023         unimplemented!()
1024     }
1025 }
1026 
bytes_to_str(bytes: &[u8]) -> &str1027 fn bytes_to_str(bytes: &[u8]) -> &str {
1028     unsafe { std::str::from_utf8_unchecked(bytes) }
1029 }
1030 
scheme_token(bytes: &[u8]) -> Result<(Option<Scheme>, &[u8]), InvalidUri>1031 fn scheme_token(bytes: &[u8]) -> Result<(Option<Scheme>, &[u8]), InvalidUri> {
1032     const HTTP_SCHEME_LENGTH: usize = "http://".len();
1033     const HTTPS_SCHEME_LENGTH: usize = "https://".len();
1034     // Obtains the position of colons that separate schemes.
1035     let pos = match bytes.iter().enumerate().find(|(_, &b)| b == b':') {
1036         Some((index, _))
1037             if index != 0
1038                 && bytes[index..].len() > 2
1039                 && bytes[index + 1..index + 3].eq_ignore_ascii_case(b"//") =>
1040         {
1041             index
1042         }
1043         Some((0, _)) => return Err(InvalidUri::InvalidScheme),
1044         _ => return Ok((None, bytes)),
1045     };
1046     // Currently, only HTTP and HTTPS are supported. Therefore, you need to verify
1047     // the scheme content.
1048     if bytes[..pos].eq_ignore_ascii_case(b"http") {
1049         Ok((Some(Protocol::Http.into()), &bytes[HTTP_SCHEME_LENGTH..]))
1050     } else if bytes[..pos].eq_ignore_ascii_case(b"https") {
1051         Ok((Some(Protocol::Https.into()), &bytes[HTTPS_SCHEME_LENGTH..]))
1052     } else {
1053         Err(InvalidUri::InvalidScheme)
1054     }
1055 }
1056 
authority_token(bytes: &[u8]) -> Result<(Option<Authority>, &[u8]), InvalidUri>1057 fn authority_token(bytes: &[u8]) -> Result<(Option<Authority>, &[u8]), InvalidUri> {
1058     let mut end = bytes.len();
1059     let mut colon_num = 0;
1060     let mut left_bracket = false;
1061     let mut right_bracket = false;
1062     for (i, &b) in bytes.iter().enumerate() {
1063         match b {
1064             b'/' | b'?' | b'#' => {
1065                 end = i;
1066                 break;
1067             }
1068             b'[' => {
1069                 if i == 0 {
1070                     left_bracket = true;
1071                 } else if left_bracket {
1072                     return Err(InvalidUri::InvalidAuthority);
1073                 }
1074             }
1075             b']' => {
1076                 if left_bracket {
1077                     if right_bracket {
1078                         return Err(InvalidUri::InvalidAuthority);
1079                     } else {
1080                         right_bracket = true;
1081                         // The ':' between '[' and ']' is in ipv6 and should be ignored.
1082                         colon_num = 0;
1083                     }
1084                 }
1085             }
1086             // TODO According to RFC3986, the character @ can be one of the reserved characters,
1087             // which needs to be improved after being familiar with the rules.
1088             b'@' => {
1089                 return Err(InvalidUri::UriContainUserinfo);
1090             }
1091             b':' => {
1092                 colon_num += 1;
1093             }
1094             other => {
1095                 if !URI_VALUE_BYTES[other as usize] {
1096                     return Err(InvalidUri::InvalidByte);
1097                 }
1098             }
1099         }
1100     }
1101     authority_parse(bytes, end, colon_num, left_bracket, right_bracket)
1102 }
1103 
authority_parse( bytes: &[u8], end: usize, colon_num: i32, left_bracket: bool, right_bracket: bool, ) -> Result<(Option<Authority>, &[u8]), InvalidUri>1104 fn authority_parse(
1105     bytes: &[u8],
1106     end: usize,
1107     colon_num: i32,
1108     left_bracket: bool,
1109     right_bracket: bool,
1110 ) -> Result<(Option<Authority>, &[u8]), InvalidUri> {
1111     // The authority does not exist.
1112     if end == 0 {
1113         return Ok((None, &bytes[end..]));
1114     }
1115 
1116     // Incomplete square brackets
1117     if left_bracket ^ right_bracket {
1118         return Err(InvalidUri::InvalidAuthority);
1119     }
1120     // There are multiple colons in addition to IPv6.
1121     if colon_num > 1 {
1122         return Err(InvalidUri::InvalidAuthority);
1123     }
1124     let authority = host_port(&bytes[..end], colon_num)?;
1125     Ok((Some(authority), &bytes[end..]))
1126 }
1127 
path_token(bytes: &[u8]) -> Result<(Option<Path>, &[u8]), InvalidUri>1128 fn path_token(bytes: &[u8]) -> Result<(Option<Path>, &[u8]), InvalidUri> {
1129     let mut end = bytes.len();
1130     for (i, &b) in bytes.iter().enumerate() {
1131         match b {
1132             b'?' | b'#' => {
1133                 end = i;
1134                 break;
1135             }
1136             _ => {
1137                 // "{} The three characters that might be used were previously percent-encoding.
1138                 if !PATH_AND_QUERY_BYTES[b as usize] {
1139                     return Err(InvalidUri::InvalidByte);
1140                 }
1141             }
1142         }
1143     }
1144     if end != 0 {
1145         let path = bytes_to_str(&bytes[..end]).to_string();
1146         Ok((Some(Path(path)), &bytes[end..]))
1147     } else {
1148         Ok((None, &bytes[end..]))
1149     }
1150 }
1151 
query_token(bytes: &[u8]) -> Result<Option<Query>, InvalidUri>1152 fn query_token(bytes: &[u8]) -> Result<Option<Query>, InvalidUri> {
1153     if bytes.is_empty() {
1154         return Ok(None);
1155     }
1156     let mut end = bytes.len();
1157     for (i, &b) in bytes.iter().enumerate() {
1158         match b {
1159             b'#' => {
1160                 end = i;
1161                 break;
1162             }
1163             // ?|  ` |  { |  }
1164             0x3F | 0x60 | 0x7B | 0x7D => {}
1165             _ => {
1166                 if !PATH_AND_QUERY_BYTES[b as usize] {
1167                     return Err(InvalidUri::InvalidByte);
1168                 }
1169             }
1170         }
1171     }
1172     if end == 0 {
1173         return Ok(None);
1174     }
1175     let query = bytes_to_str(&bytes[..end]);
1176     Ok(Some(Query(query.to_string())))
1177 }
1178 
host_port(auth: &[u8], colon_num: i32) -> Result<Authority, InvalidUri>1179 fn host_port(auth: &[u8], colon_num: i32) -> Result<Authority, InvalidUri> {
1180     let authority = bytes_to_str(auth);
1181     if colon_num != 0 {
1182         match authority.rsplit_once(':') {
1183             Some((host, port)) => {
1184                 if host.is_empty() {
1185                     Err(InvalidUri::UriMissHost)
1186                 } else if port.is_empty() {
1187                     Ok(Authority {
1188                         host: Host(host.to_string()),
1189                         port: None,
1190                     })
1191                 } else {
1192                     port.parse::<u16>().map_err(|_| InvalidUri::InvalidPort)?;
1193                     Ok(Authority {
1194                         host: Host(host.to_string()),
1195                         port: Some(Port(port.to_string())),
1196                     })
1197                 }
1198             }
1199             None => Err(InvalidUri::UriMissAuthority),
1200         }
1201     } else {
1202         Ok(Authority {
1203             host: Host(authority.to_string()),
1204             port: None,
1205         })
1206     }
1207 }
1208 
validity_check(unchecked_uri: Uri) -> Result<Uri, InvalidUri>1209 fn validity_check(unchecked_uri: Uri) -> Result<Uri, InvalidUri> {
1210     match (
1211         &unchecked_uri.scheme,
1212         &unchecked_uri.authority,
1213         &unchecked_uri.path,
1214         &unchecked_uri.query,
1215     ) {
1216         (Some(_), None, _, _) => Err(InvalidUri::UriMissAuthority),
1217         (None, Some(_), Some(_), _) => Err(InvalidUri::UriMissScheme),
1218         (None, Some(_), _, Some(_)) => Err(InvalidUri::UriMissScheme),
1219         (None, None, None, None) => Err(InvalidUri::InvalidFormat),
1220         _ => Ok(unchecked_uri),
1221     }
1222 }
1223 
1224 #[rustfmt::skip]
1225 const URI_VALUE_BYTES: [bool; 256] = {
1226     const __: bool = false;
1227     const TT: bool = true;
1228     [
1229 //      \0                                  HT  LF          CR
1230         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F
1231         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 1F
1232 //      \w  !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
1233         __, TT, __, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 2F
1234 //      0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
1235         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, __, TT, __, TT, // 3F
1236 //      @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
1237         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 4F
1238 //      P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _
1239         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, __, TT, __, TT, // 5F
1240 //      `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
1241         __, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 6F
1242 //      p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~   del
1243         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, __, __, __, TT, __, // 7F
1244 //      Expand ascii
1245         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8F
1246         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9F
1247         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // AF
1248         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // BF
1249         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // CF
1250         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // DF
1251         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // EF
1252         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // FF
1253     ]
1254 };
1255 
1256 #[rustfmt::skip]
1257 const PATH_AND_QUERY_BYTES: [bool; 256] = {
1258     const __: bool = false;
1259     const TT: bool = true;
1260     [
1261 //      \0                                  HT  LF          CR
1262         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F
1263         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 1F
1264 //      \w  !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
1265         __, TT, __, __, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 2F
1266 //      0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
1267         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, __, TT, __, __, // 3F
1268 //      @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
1269         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 4F
1270 //      P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _
1271         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 5F
1272 //      `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
1273         __, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 6F
1274 //      p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~   del
1275         TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, __, TT, __, TT, __, // 7F
1276 //      Expand ascii
1277         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8F
1278         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9F
1279         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // AF
1280         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // BF
1281         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // CF
1282         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // DF
1283         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // EF
1284         __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // FF
1285     ]
1286 };
1287 
1288 #[cfg(test)]
1289 mod ut_uri {
1290     use super::{InvalidUri, Scheme, Uri, UriBuilder};
1291     use crate::error::{ErrorKind, HttpError};
1292 
1293     macro_rules! test_builder_valid {
1294         ($res1:expr, $res2:expr) => {{
1295             let uri = UriBuilder::new()
1296                 .scheme($res1.0)
1297                 .authority($res1.1)
1298                 .path($res1.2)
1299                 .query($res1.3)
1300                 .build()
1301                 .unwrap();
1302             assert_eq!(uri.scheme().unwrap().as_str(), $res2.0);
1303             assert_eq!(uri.host().unwrap().as_str(), $res2.1);
1304             assert_eq!(uri.port().unwrap().as_str(), $res2.2);
1305             assert_eq!(uri.path().unwrap().as_str(), $res2.3);
1306             assert_eq!(uri.query().unwrap().as_str(), $res2.4);
1307             assert_eq!(uri.to_string(), $res2.5)
1308         }};
1309     }
1310 
1311     /// UT test cases for `build_from_builder`.
1312     ///
1313     /// # Brief
1314     /// 1. Creates UriBuilder by calling UriBuilder::new().
1315     /// 2. Sets Scheme by calling scheme().
1316     /// 3. Sets authority by calling authority().
1317     /// 4. Sets path by calling path().
1318     /// 5. Sets query by calling query().
1319     /// 6. Creates Uri by calling build().
1320     /// 7. Gets string slice value of uri components by calling as_str().
1321     /// 8. Gets string value of uri by calling to_string().
1322     /// 9. Checks if the test result is correct by assert_eq!().
1323     #[test]
build_from_builder()1324     fn build_from_builder() {
1325         test_builder_valid!(
1326             ("http", "hyper.rs:80", "/foo", "a=1"),
1327             (
1328                 "http",
1329                 "hyper.rs",
1330                 "80",
1331                 "/foo",
1332                 "a=1",
1333                 "http://hyper.rs:80/foo?a=1"
1334             )
1335         );
1336         test_builder_valid!(
1337             (Scheme::HTTP, "hyper.rs:80", "/foo", "a=1"),
1338             (
1339                 "http",
1340                 "hyper.rs",
1341                 "80",
1342                 "/foo",
1343                 "a=1",
1344                 "http://hyper.rs:80/foo?a=1"
1345             )
1346         );
1347         test_builder_valid!(
1348             ("https", "hyper.rs:80", "/foo", "a=1"),
1349             (
1350                 "https",
1351                 "hyper.rs",
1352                 "80",
1353                 "/foo",
1354                 "a=1",
1355                 "https://hyper.rs:80/foo?a=1"
1356             )
1357         );
1358         test_builder_valid!(
1359             (Scheme::HTTPS, "hyper.rs:80", "/foo", "a=1"),
1360             (
1361                 "https",
1362                 "hyper.rs",
1363                 "80",
1364                 "/foo",
1365                 "a=1",
1366                 "https://hyper.rs:80/foo?a=1"
1367             )
1368         );
1369     }
1370 
1371     /// UT test cases for `build_from_instance`.
1372     ///
1373     /// # Brief
1374     /// 1. Creates UriBuilder by calling Uri::builder().
1375     /// 2. Sets Scheme by calling scheme().
1376     /// 3. Sets authority by calling authority().
1377     /// 4. Sets path by calling path().
1378     /// 5. Sets query by calling query().
1379     /// 6. Creates Uri by calling build().
1380     /// 7. Gets string slice value of uri components by calling as_str().
1381     /// 8. Gets string value of uri by calling to_string().
1382     /// 9. Checks if the test result is correct by assert_eq!().
1383     #[test]
build_from_instance()1384     fn build_from_instance() {
1385         let uri = Uri::builder()
1386             .scheme(Scheme::HTTP)
1387             .authority("hyper.rs:80")
1388             .path("/foo")
1389             .query("a=1")
1390             .build()
1391             .unwrap();
1392         assert_eq!(uri.scheme().unwrap().as_str(), "http");
1393         assert_eq!(uri.host().unwrap().as_str(), "hyper.rs");
1394         assert_eq!(uri.port().unwrap().as_str(), "80");
1395         assert_eq!(uri.path().unwrap().as_str(), "/foo");
1396         assert_eq!(uri.query().unwrap().as_str(), "a=1");
1397         assert_eq!(uri.to_string(), "http://hyper.rs:80/foo?a=1")
1398     }
1399 
1400     /// UT test cases for `build_from_str`.
1401     ///
1402     /// # Brief
1403     /// 1. Creates Uri by calling from_bytes().
1404     /// 2. Gets string slice value of uri components by calling as_str().
1405     /// 3. Gets u16 value of port by call as_u16().
1406     /// 4. Gets string value of uri by calling to_string().
1407     /// 5. Checks if the test result is correct by assert_eq!().
1408     #[test]
build_from_str()1409     fn build_from_str() {
1410         let uri = Uri::from_bytes("http://hyper.rs:80/foo?a=1".as_bytes()).unwrap();
1411         assert_eq!(uri.scheme().unwrap().as_str(), "http");
1412         assert_eq!(uri.host().unwrap().as_str(), "hyper.rs");
1413         assert_eq!(uri.port().unwrap().as_str(), "80");
1414         assert_eq!(uri.port().unwrap().as_u16().unwrap(), 80);
1415         assert_eq!(uri.path().unwrap().as_str(), "/foo");
1416         assert_eq!(uri.query().unwrap().as_str(), "a=1");
1417         assert_eq!(uri.to_string(), "http://hyper.rs:80/foo?a=1")
1418     }
1419 
1420     /// UT test cases for `Scheme::default_port`.
1421     ///
1422     /// # Brief
1423     /// 1. Creates Scheme by calling `Scheme::from_bytes`.
1424     /// 3. Gets u16 value of port by calling `Scheme::default_port`.
1425     /// 5. Checks whether the default port is correct.
1426     #[test]
ut_uri_scheme_default_port()1427     fn ut_uri_scheme_default_port() {
1428         let scheme = Scheme::from_bytes(b"http").unwrap();
1429         assert_eq!(scheme.default_port(), 80);
1430         let scheme = Scheme::from_bytes(b"https").unwrap();
1431         assert_eq!(scheme.default_port(), 443);
1432     }
1433 
1434     /// UT test cases for `Uri::from_bytes`.
1435     ///
1436     /// # Brief
1437     /// 1. Creates Uri by calling `Uri::from_bytes()`.
1438     /// 2. Checks if the test results are correct.
1439     #[test]
ut_uri_from_bytes()1440     fn ut_uri_from_bytes() {
1441         macro_rules! uri_test_case {
1442             ($raw: expr, $tar: expr, $(,)?) => {
1443                 match (Uri::from_bytes($raw), $tar) {
1444                     (Ok(res), Ok(tar)) => assert_eq!(
1445                         (
1446                             res.scheme().map(|scheme| scheme.as_str()),
1447                             res.host().map(|host| host.as_str()),
1448                             res.port().map(|port| port.as_str()),
1449                             res.path().map(|path| path.as_str()),
1450                             res.query().map(|query| query.as_str()),
1451                         ),
1452                         tar,
1453                     ),
1454                     (Err(res), Err(tar)) => assert_eq!(res, tar),
1455                     _ => panic!("uri test case failed!"),
1456                 }
1457             };
1458         }
1459 
1460         uri_test_case!(
1461             b"httpss://www.example.com/",
1462             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidScheme))),
1463         );
1464 
1465         uri_test_case!(
1466             b"://www.example.com/",
1467             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidScheme))),
1468         );
1469 
1470         uri_test_case!(
1471             b"https://www.hu awei.com/",
1472             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1473         );
1474 
1475         uri_test_case!(
1476             br#"https://www.hu"awei.com/"#,
1477             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1478         );
1479 
1480         uri_test_case!(
1481             br#"https://www.hu"awei.com/"#,
1482             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1483         );
1484 
1485         uri_test_case!(
1486             br#"https://www.hu"<>\^`awei.com/"#,
1487             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1488         );
1489 
1490         uri_test_case!(
1491             br#"https://www.example.com:a0/"#,
1492             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidPort))),
1493         );
1494 
1495         uri_test_case!(
1496             br#"https://www.example.com:80/message/e<>mail"#,
1497             Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1498         );
1499 
1500         uri_test_case!(
1501             br#"https:/www.example.com:80/message/email?name=arya"#,
1502             Err(HttpError::from(ErrorKind::Uri(InvalidUri::UriMissScheme))),
1503         );
1504 
1505         uri_test_case!(
1506             br#"https:/www.example.com:80"#,
1507             Err(HttpError::from(ErrorKind::Uri(InvalidUri::UriMissScheme))),
1508         );
1509 
1510         uri_test_case!(
1511             br#"https:/www.example.com"#,
1512             Err(HttpError::from(ErrorKind::Uri(InvalidUri::UriMissScheme))),
1513         );
1514 
1515         uri_test_case!(
1516             br#"https://www.huaw:ei.com:80"#,
1517             Err(HttpError::from(ErrorKind::Uri(
1518                 InvalidUri::InvalidAuthority
1519             ))),
1520         );
1521 
1522         uri_test_case!(
1523             br#"https://www.huaw:ei.com:80"#,
1524             Err(HttpError::from(ErrorKind::Uri(
1525                 InvalidUri::InvalidAuthority
1526             ))),
1527         );
1528 
1529         uri_test_case!(
1530             br#"https://name=1234@www.example.com:80/message/email?name=arya"#,
1531             Err(HttpError::from(ErrorKind::Uri(
1532                 InvalidUri::UriContainUserinfo
1533             ))),
1534         );
1535 
1536         uri_test_case!(
1537             br#"www.example.com:80/message/email?name=arya"#,
1538             Err(HttpError::from(ErrorKind::Uri(InvalidUri::UriMissScheme))),
1539         );
1540 
1541         uri_test_case!(
1542             br#"https://[0:0:0:0:0:0:0:0:80/message/email?name=arya"#,
1543             Err(HttpError::from(ErrorKind::Uri(
1544                 InvalidUri::InvalidAuthority
1545             ))),
1546         );
1547 
1548         uri_test_case!(
1549             br#"https:///foo?a=1"#,
1550             Err(HttpError::from(ErrorKind::Uri(
1551                 InvalidUri::UriMissAuthority
1552             ))),
1553         );
1554 
1555         uri_test_case!(
1556             b"https://www.example.com/",
1557             Ok((
1558                 Some("https"),
1559                 Some("www.example.com"),
1560                 None,
1561                 Some("/"),
1562                 None
1563             )),
1564         );
1565 
1566         uri_test_case!(
1567             b"https://www.example.com:80/foo?a=1",
1568             Ok((
1569                 Some("https"),
1570                 Some("www.example.com"),
1571                 Some("80"),
1572                 Some("/foo"),
1573                 Some("a=1"),
1574             )),
1575         );
1576 
1577         uri_test_case!(
1578             b"https://www.example.com:80/foo?a=1#fragment",
1579             Ok((
1580                 Some("https"),
1581                 Some("www.example.com"),
1582                 Some("80"),
1583                 Some("/foo"),
1584                 Some("a=1"),
1585             )),
1586         );
1587 
1588         uri_test_case!(
1589             b"https://www.example.com:80?a=1",
1590             Ok((
1591                 Some("https"),
1592                 Some("www.example.com"),
1593                 Some("80"),
1594                 None,
1595                 Some("a=1"),
1596             )),
1597         );
1598 
1599         uri_test_case!(
1600             b"https://www.example.com?a=1",
1601             Ok((
1602                 Some("https"),
1603                 Some("www.example.com"),
1604                 None,
1605                 None,
1606                 Some("a=1"),
1607             )),
1608         );
1609 
1610         uri_test_case!(
1611             b"https://www.example.com?",
1612             Ok((Some("https"), Some("www.example.com"), None, None, None)),
1613         );
1614 
1615         uri_test_case!(
1616             b"https://www.example.com:80",
1617             Ok((
1618                 Some("https"),
1619                 Some("www.example.com"),
1620                 Some("80"),
1621                 None,
1622                 None,
1623             )),
1624         );
1625 
1626         uri_test_case!(
1627             b"https://www.example.com",
1628             Ok((Some("https"), Some("www.example.com"), None, None, None)),
1629         );
1630 
1631         uri_test_case!(
1632             b"https://www.example.com#fragment",
1633             Ok((Some("https"), Some("www.example.com"), None, None, None)),
1634         );
1635 
1636         uri_test_case!(
1637             b"www.example.com",
1638             Ok((None, Some("www.example.com"), None, None, None)),
1639         );
1640 
1641         uri_test_case!(
1642             b"/foo?a=1",
1643             Ok((None, None, None, Some("/foo"), Some("a=1"))),
1644         );
1645 
1646         uri_test_case!(
1647             b"https://[0:0:0:0:0:0:0:0]",
1648             Ok((Some("https"), Some("[0:0:0:0:0:0:0:0]"), None, None, None)),
1649         );
1650 
1651         uri_test_case!(
1652             b"https://[0:0:0:0:0:0:0:0]:80",
1653             Ok((
1654                 Some("https"),
1655                 Some("[0:0:0:0:0:0:0:0]"),
1656                 Some("80"),
1657                 None,
1658                 None,
1659             )),
1660         );
1661     }
1662 
1663     /// UT test cases for `Uri::authority`.
1664     ///
1665     /// # Brief
1666     /// 1. Creates Uri by calling `Uri::authority()`.
1667     /// 2. Checks if the test results are correct.
1668     #[test]
ut_uri_authority()1669     fn ut_uri_authority() {
1670         let uri = Uri::from_bytes(b"http://example.com:8080/foo?a=1").unwrap();
1671         let authority = uri.authority().unwrap();
1672         assert_eq!(authority.host.as_str(), "example.com");
1673         assert_eq!(authority.port().unwrap().as_str(), "8080");
1674     }
1675 
1676     /// UT test cases for `Uri::path_and_query`.
1677     ///
1678     /// # Brief
1679     /// 1. Creates Uri by calling `Uri::path_and_query()`.
1680     /// 2. Checks if the test results are correct.
1681     #[test]
ut_uri_path_and_query()1682     fn ut_uri_path_and_query() {
1683         let uri = Uri::from_bytes(b"http://example.com:8080/foo?a=1").unwrap();
1684         assert_eq!(uri.path_and_query().unwrap(), "/foo?a=1");
1685 
1686         let uri = Uri::from_bytes(b"http://example.com:8080").unwrap();
1687         assert_eq!(uri.path_and_query(), None);
1688     }
1689 
1690     /// UT test cases for `Uri::path_and_query`.
1691     ///
1692     /// # Brief
1693     /// 1. Creates Uri by calling `Uri::path_and_query()`.
1694     /// 2. Checks that the query containing the {} symbol parses properly.
1695     #[test]
ut_uri_json_query()1696     fn ut_uri_json_query() {
1697         let uri = Uri::from_bytes(b"http://example.com:8080/foo?a=1{WEBO_TEST}").unwrap();
1698         assert_eq!(uri.path_and_query().unwrap(), "/foo?a=1{WEBO_TEST}");
1699     }
1700 }
1701