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