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