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