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
558 impl From<Protocol> for Scheme {
from(proto: Protocol) -> Self559 fn from(proto: Protocol) -> Self {
560 Scheme { proto }
561 }
562 }
563
564 impl<'a> TryFrom<&'a [u8]> for Scheme {
565 type Error = InvalidUri;
566
try_from(bytes: &'a [u8]) -> Result<Self, Self::Error>567 fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
568 Scheme::from_bytes(bytes)
569 }
570 }
571
572 impl<'a> TryFrom<&'a str> for Scheme {
573 type Error = InvalidUri;
574
try_from(s: &'a str) -> Result<Self, Self::Error>575 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
576 TryFrom::try_from(s.as_bytes())
577 }
578 }
579
580 /// Authority component of [`Uri`].
581 ///
582 /// [`Uri`]: Uri
583 #[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
584 pub struct Authority {
585 host: Host,
586 port: Option<Port>,
587 }
588
589 impl Authority {
590 /// Converts a byte slice into a `Authority`.
591 ///
592 /// # Examples
593 ///
594 /// ```
595 /// use ylong_http::request::uri::Authority;
596 ///
597 /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
598 /// ```
from_bytes(bytes: &[u8]) -> Result<Authority, InvalidUri>599 pub fn from_bytes(bytes: &[u8]) -> Result<Authority, InvalidUri> {
600 if bytes.is_empty() {
601 return Err(InvalidUri::UriMissAuthority);
602 }
603 let (authority, rest) = authority_token(bytes)?;
604 if !rest.is_empty() || authority.is_none() {
605 return Err(InvalidUri::InvalidAuthority);
606 }
607 Ok(authority.unwrap())
608 }
609
610 /// Gets a immutable reference to `Host`.
611 ///
612 /// # Examples
613 ///
614 /// ```
615 /// use ylong_http::request::uri::{Authority, Host};
616 ///
617 /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
618 /// let host = authority.host();
619 /// assert_eq!(host.as_str(), "example.com");
620 /// ```
host(&self) -> &Host621 pub fn host(&self) -> &Host {
622 &self.host
623 }
624
625 /// Gets a immutable reference to `Port`.
626 ///
627 /// # Examples
628 ///
629 /// ```
630 /// use ylong_http::request::uri::{Authority, Port};
631 ///
632 /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
633 /// let port = authority.port().unwrap();
634 /// assert_eq!(port.as_str(), "80");
635 /// ```
port(&self) -> Option<&Port>636 pub fn port(&self) -> Option<&Port> {
637 self.port.as_ref()
638 }
639
640 /// Returns a string containing the entire `Authority`.
641 ///
642 /// # Examples
643 ///
644 /// ```
645 /// use ylong_http::request::uri::{Authority, Port};
646 ///
647 /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
648 /// assert_eq!(authority.to_str(), "example.com:80".to_string());
649 /// ```
to_str(&self) -> String650 pub fn to_str(&self) -> String {
651 let mut auth = self.host.as_str().to_string();
652 if let Some(ref p) = self.port {
653 auth.push(':');
654 auth.push_str(p.as_str());
655 };
656 auth
657 }
658
659 /// Splits the `Authority` into its parts.
660 ///
661 /// # Examples
662 ///
663 /// ```
664 /// use ylong_http::request::uri::Authority;
665 ///
666 /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
667 /// let (host, port) = authority.into_parts();
668 /// assert_eq!(host.as_str(), "example.com");
669 /// assert_eq!(port.unwrap().as_u16().unwrap(), 80);
670 /// ```
into_parts(self) -> (Host, Option<Port>)671 pub fn into_parts(self) -> (Host, Option<Port>) {
672 (self.host, self.port)
673 }
674 }
675
676 impl<'a> TryFrom<&'a [u8]> for Authority {
677 type Error = InvalidUri;
678
try_from(bytes: &'a [u8]) -> Result<Self, Self::Error>679 fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
680 Authority::from_bytes(bytes)
681 }
682 }
683
684 impl<'a> TryFrom<&'a str> for Authority {
685 type Error = InvalidUri;
686
try_from(s: &'a str) -> Result<Self, Self::Error>687 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
688 TryFrom::try_from(s.as_bytes())
689 }
690 }
691
692 impl ToString for Authority {
to_string(&self) -> String693 fn to_string(&self) -> String {
694 let mut builder = String::new();
695 builder.push_str(self.host().as_str());
696 if let Some(port) = self.port() {
697 builder.push(':');
698 builder.push_str(port.as_str());
699 }
700 builder
701 }
702 }
703
704 /// Host part of [`Authority`].
705 ///
706 /// [`Authority`]: Authority
707 #[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
708 pub struct Host(String);
709
710 impl Host {
711 /// Returns a string slice containing the entire `Host`.
712 ///
713 /// # Examples
714 ///
715 /// ```
716 /// use ylong_http::request::uri::Authority;
717 ///
718 /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
719 /// let host = authority.host();
720 /// assert_eq!(host.as_str(), "example.com");
721 /// ```
as_str(&self) -> &str722 pub fn as_str(&self) -> &str {
723 self.0.as_str()
724 }
725 }
726
727 impl ToString for Host {
to_string(&self) -> String728 fn to_string(&self) -> String {
729 self.0.to_owned()
730 }
731 }
732
733 /// Port part of [`Authority`].
734 ///
735 /// [`Authority`]: Authority
736 #[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
737 pub struct Port(String);
738
739 impl Port {
740 /// Returns a string slice containing the entire `Port`.
741 ///
742 /// # Examples
743 ///
744 /// ```
745 /// use ylong_http::request::uri::{Authority, Port};
746 ///
747 /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
748 /// let port = authority.port().unwrap();
749 /// assert_eq!(port.as_str(), "80");
750 /// ```
as_str(&self) -> &str751 pub fn as_str(&self) -> &str {
752 self.0.as_str()
753 }
754
755 /// Returns a u16 value of the `Port`.
756 ///
757 /// # Examples
758 ///
759 /// ```
760 /// use ylong_http::request::uri::{Authority, Port};
761 ///
762 /// let authority = Authority::from_bytes(b"example.com:80").unwrap();
763 /// let port = authority.port().unwrap();
764 /// assert_eq!(port.as_u16().unwrap(), 80);
765 /// ```
as_u16(&self) -> Result<u16, HttpError>766 pub fn as_u16(&self) -> Result<u16, HttpError> {
767 self.0
768 .parse::<u16>()
769 .map_err(|_| ErrorKind::Uri(InvalidUri::InvalidPort).into())
770 }
771 }
772
773 /// Path component of [`Uri`].
774 ///
775 /// [`Uri`]: Uri
776 #[derive(Clone, Debug, Default)]
777 pub struct Path(String);
778
779 impl Path {
780 /// Converts a byte slice into a `Path`.
781 ///
782 /// # Examples
783 ///
784 /// ```
785 /// use ylong_http::request::uri::Path;
786 ///
787 /// let path = Path::from_bytes(b"/foo").unwrap();
788 /// assert_eq!(path.as_str(), "/foo");
789 /// ```
from_bytes(bytes: &[u8]) -> Result<Path, InvalidUri>790 pub fn from_bytes(bytes: &[u8]) -> Result<Path, InvalidUri> {
791 let (path, rest) = path_token(bytes)?;
792 if rest.is_empty() {
793 path.ok_or(InvalidUri::UriMissPath)
794 } else {
795 Err(InvalidUri::InvalidPath)
796 }
797 }
798
799 /// Returns a string slice containing the entire `Path`.
800 ///
801 /// # Examples
802 ///
803 /// ```
804 /// use ylong_http::request::uri::Path;
805 ///
806 /// let path = Path::from_bytes(b"/foo").unwrap();
807 /// assert_eq!(path.as_str(), "/foo");
808 /// ```
as_str(&self) -> &str809 pub fn as_str(&self) -> &str {
810 self.0.as_str()
811 }
812 }
813
814 impl<'a> TryFrom<&'a [u8]> for Path {
815 type Error = InvalidUri;
816
try_from(bytes: &'a [u8]) -> Result<Self, Self::Error>817 fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
818 Path::from_bytes(bytes)
819 }
820 }
821
822 impl<'a> TryFrom<&'a str> for Path {
823 type Error = InvalidUri;
824
try_from(s: &'a str) -> Result<Self, Self::Error>825 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
826 TryFrom::try_from(s.as_bytes())
827 }
828 }
829
830 /// Query component of [`Uri`].
831 ///
832 /// [`Uri`]: Uri
833 #[derive(Clone, Debug, Default)]
834 pub struct Query(String);
835
836 impl Query {
837 /// Converts a byte slice into a `Query`.
838 ///
839 /// # Examples
840 ///
841 /// ```
842 /// use ylong_http::request::uri::Query;
843 ///
844 /// let query = Query::from_bytes(b"a=1").unwrap();
845 /// assert_eq!(query.as_str(), "a=1");
846 /// ```
from_bytes(bytes: &[u8]) -> Result<Query, InvalidUri>847 pub fn from_bytes(bytes: &[u8]) -> Result<Query, InvalidUri> {
848 let query = query_token(bytes)?;
849 query.ok_or(InvalidUri::UriMissQuery)
850 }
851
852 /// Returns a string slice containing the entire `Query`.
853 ///
854 /// # Examples
855 ///
856 /// ```
857 /// use ylong_http::request::uri::Query;
858 ///
859 /// let query = Query::from_bytes(b"a=1").unwrap();
860 /// assert_eq!(query.as_str(), "a=1");
861 /// ```
as_str(&self) -> &str862 pub fn as_str(&self) -> &str {
863 self.0.as_str()
864 }
865 }
866
867 impl<'a> TryFrom<&'a [u8]> for Query {
868 type Error = InvalidUri;
869
try_from(s: &'a [u8]) -> Result<Self, Self::Error>870 fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
871 Query::from_bytes(s)
872 }
873 }
874
875 impl<'a> TryFrom<&'a str> for Query {
876 type Error = InvalidUri;
877
try_from(s: &'a str) -> Result<Self, Self::Error>878 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
879 TryFrom::try_from(s.as_bytes())
880 }
881 }
882
883 /// `Protocol` indicates the scheme type supported by [`Uri`].
884 ///
885 /// [`Uri`]: Uri
886 #[derive(Clone, Debug, Eq, PartialEq, Hash)]
887 enum Protocol {
888 Http,
889 Https,
890 }
891
892 /// Error types generated during [`Uri`] construction due to different causes.
893 ///
894 /// [`Uri`]: Uri
895 #[derive(Debug, Eq, PartialEq)]
896 pub enum InvalidUri {
897 /// Invalid scheme
898 InvalidScheme,
899 /// Invalid authority
900 InvalidAuthority,
901 /// Invalid path
902 InvalidPath,
903 /// Invalid byte
904 InvalidByte,
905 /// Invalid format
906 InvalidFormat,
907 /// Invalid port
908 InvalidPort,
909 /// Missing scheme
910 UriMissScheme,
911 /// Missing path
912 UriMissPath,
913 /// Missing query
914 UriMissQuery,
915 /// Missing authority
916 UriMissAuthority,
917 /// Missing host
918 UriMissHost,
919 /// Contains Userinfo
920 UriContainUserinfo,
921 /// Too long
922 UriTooLong,
923 }
924
925 impl From<Infallible> for InvalidUri {
from(_: Infallible) -> Self926 fn from(_: Infallible) -> Self {
927 unimplemented!()
928 }
929 }
930
bytes_to_str(bytes: &[u8]) -> &str931 fn bytes_to_str(bytes: &[u8]) -> &str {
932 unsafe { std::str::from_utf8_unchecked(bytes) }
933 }
934
scheme_token(bytes: &[u8]) -> Result<(Option<Scheme>, &[u8]), InvalidUri>935 fn scheme_token(bytes: &[u8]) -> Result<(Option<Scheme>, &[u8]), InvalidUri> {
936 const HTTP_SCHEME_LENGTH: usize = "http://".len();
937 const HTTPS_SCHEME_LENGTH: usize = "https://".len();
938 // Obtains the position of colons that separate schemes.
939 let pos = match bytes.iter().enumerate().find(|(_, &b)| b == b':') {
940 Some((index, _))
941 if index != 0
942 && bytes[index..].len() > 2
943 && bytes[index + 1..index + 3].eq_ignore_ascii_case(b"//") =>
944 {
945 index
946 }
947 Some((0, _)) => return Err(InvalidUri::InvalidScheme),
948 _ => return Ok((None, bytes)),
949 };
950 // Currently, only HTTP and HTTPS are supported. Therefore, you need to verify
951 // the scheme content.
952 if bytes[..pos].eq_ignore_ascii_case(b"http") {
953 Ok((Some(Protocol::Http.into()), &bytes[HTTP_SCHEME_LENGTH..]))
954 } else if bytes[..pos].eq_ignore_ascii_case(b"https") {
955 Ok((Some(Protocol::Https.into()), &bytes[HTTPS_SCHEME_LENGTH..]))
956 } else {
957 Err(InvalidUri::InvalidScheme)
958 }
959 }
960
authority_token(bytes: &[u8]) -> Result<(Option<Authority>, &[u8]), InvalidUri>961 fn authority_token(bytes: &[u8]) -> Result<(Option<Authority>, &[u8]), InvalidUri> {
962 let mut end = bytes.len();
963 let mut colon_num = 0;
964 let mut left_bracket = false;
965 let mut right_bracket = false;
966 for (i, &b) in bytes.iter().enumerate() {
967 match b {
968 b'/' | b'?' | b'#' => {
969 end = i;
970 break;
971 }
972 b'[' => {
973 if i == 0 {
974 left_bracket = true;
975 } else if left_bracket {
976 return Err(InvalidUri::InvalidAuthority);
977 }
978 }
979 b']' => {
980 if left_bracket {
981 if right_bracket {
982 return Err(InvalidUri::InvalidAuthority);
983 } else {
984 right_bracket = true;
985 // The ':' between '[' and ']' is in ipv6 and should be ignored.
986 colon_num = 0;
987 }
988 }
989 }
990 // TODO According to RFC3986, the character @ can be one of the reserved characters,
991 // which needs to be improved after being familiar with the rules.
992 b'@' => {
993 return Err(InvalidUri::UriContainUserinfo);
994 }
995 b':' => {
996 colon_num += 1;
997 }
998 other => {
999 if !URI_VALUE_BYTES[other as usize] {
1000 return Err(InvalidUri::InvalidByte);
1001 }
1002 }
1003 }
1004 }
1005 // The authority does not exist.
1006 if end == 0 {
1007 return Ok((None, &bytes[end..]));
1008 }
1009
1010 // Incomplete square brackets
1011 if left_bracket ^ right_bracket {
1012 return Err(InvalidUri::InvalidAuthority);
1013 }
1014 // There are multiple colons in addition to IPv6.
1015 if colon_num > 1 {
1016 return Err(InvalidUri::InvalidAuthority);
1017 }
1018 let authority = host_port(&bytes[..end], colon_num)?;
1019 Ok((Some(authority), &bytes[end..]))
1020 }
1021
path_token(bytes: &[u8]) -> Result<(Option<Path>, &[u8]), InvalidUri>1022 fn path_token(bytes: &[u8]) -> Result<(Option<Path>, &[u8]), InvalidUri> {
1023 let mut end = bytes.len();
1024 for (i, &b) in bytes.iter().enumerate() {
1025 match b {
1026 b'?' | b'#' => {
1027 end = i;
1028 break;
1029 }
1030 _ => {
1031 if !URI_VALUE_BYTES[b as usize] {
1032 return Err(InvalidUri::InvalidByte);
1033 }
1034 }
1035 }
1036 }
1037 if end != 0 {
1038 let path = bytes_to_str(&bytes[..end]).to_string();
1039 Ok((Some(Path(path)), &bytes[end..]))
1040 } else {
1041 Ok((None, &bytes[end..]))
1042 }
1043 }
1044
query_token(s: &[u8]) -> Result<Option<Query>, InvalidUri>1045 fn query_token(s: &[u8]) -> Result<Option<Query>, InvalidUri> {
1046 if s.is_empty() {
1047 return Ok(None);
1048 }
1049 let bytes = if s[0].eq_ignore_ascii_case(&b'?') {
1050 &s[1..]
1051 } else {
1052 s
1053 };
1054 let mut end = bytes.len();
1055 for (i, &b) in bytes.iter().enumerate() {
1056 match b {
1057 b'#' => {
1058 end = i;
1059 break;
1060 }
1061 _ => {
1062 if !URI_VALUE_BYTES[b as usize] {
1063 return Err(InvalidUri::InvalidByte);
1064 }
1065 }
1066 }
1067 }
1068 if end == 0 {
1069 return Ok(None);
1070 }
1071 let query = bytes_to_str(&bytes[..end]);
1072 Ok(Some(Query(query.to_string())))
1073 }
1074
host_port(auth: &[u8], colon_num: i32) -> Result<Authority, InvalidUri>1075 fn host_port(auth: &[u8], colon_num: i32) -> Result<Authority, InvalidUri> {
1076 let authority = bytes_to_str(auth);
1077 if colon_num != 0 {
1078 match authority.rsplit_once(':') {
1079 Some((host, port)) => {
1080 if host.is_empty() {
1081 Err(InvalidUri::UriMissHost)
1082 } else if port.is_empty() {
1083 Ok(Authority {
1084 host: Host(host.to_string()),
1085 port: None,
1086 })
1087 } else {
1088 port.parse::<u16>().map_err(|_| InvalidUri::InvalidPort)?;
1089 Ok(Authority {
1090 host: Host(host.to_string()),
1091 port: Some(Port(port.to_string())),
1092 })
1093 }
1094 }
1095 None => Err(InvalidUri::UriMissAuthority),
1096 }
1097 } else {
1098 Ok(Authority {
1099 host: Host(authority.to_string()),
1100 port: None,
1101 })
1102 }
1103 }
1104
validity_check(unchecked_uri: Uri) -> Result<Uri, InvalidUri>1105 fn validity_check(unchecked_uri: Uri) -> Result<Uri, InvalidUri> {
1106 match (
1107 &unchecked_uri.scheme,
1108 &unchecked_uri.authority,
1109 &unchecked_uri.path,
1110 &unchecked_uri.query,
1111 ) {
1112 (Some(_), None, _, _) => Err(InvalidUri::UriMissAuthority),
1113 (None, Some(_), Some(_), _) => Err(InvalidUri::UriMissScheme),
1114 (None, Some(_), _, Some(_)) => Err(InvalidUri::UriMissScheme),
1115 (None, None, None, None) => Err(InvalidUri::InvalidFormat),
1116 _ => Ok(unchecked_uri),
1117 }
1118 }
1119
1120 #[rustfmt::skip]
1121 const URI_VALUE_BYTES: [bool; 256] = {
1122 const __: bool = false;
1123 const TT: bool = true;
1124 [
1125 // \0 HT LF CR
1126 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F
1127 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 1F
1128 // \w ! " # $ % & ' ( ) * + , - . /
1129 __, TT, __, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 2F
1130 // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
1131 TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, __, TT, __, TT, // 3F
1132 // @ A B C D E F G H I J K L M N O
1133 TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 4F
1134 // P Q R S T U V W X Y Z [ \ ] ^ _
1135 TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, __, TT, __, TT, // 5F
1136 // ` a b c d e f g h i j k l m n o
1137 __, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, // 6F
1138 // p q r s t u v w x y z { | } ~ del
1139 TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, TT, __, __, __, TT, __, // 7F
1140 // Expand ascii
1141 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8F
1142 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9F
1143 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // AF
1144 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // BF
1145 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // CF
1146 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // DF
1147 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // EF
1148 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // FF
1149 ]
1150 };
1151
1152 #[cfg(test)]
1153 mod ut_uri {
1154 use super::{InvalidUri, Scheme, Uri, UriBuilder};
1155 use crate::error::{ErrorKind, HttpError};
1156
1157 macro_rules! test_builder_valid {
1158 ($res1:expr, $res2:expr) => {{
1159 let uri = UriBuilder::new()
1160 .scheme($res1.0)
1161 .authority($res1.1)
1162 .path($res1.2)
1163 .query($res1.3)
1164 .build()
1165 .unwrap();
1166 assert_eq!(uri.scheme().unwrap().as_str(), $res2.0);
1167 assert_eq!(uri.host().unwrap().as_str(), $res2.1);
1168 assert_eq!(uri.port().unwrap().as_str(), $res2.2);
1169 assert_eq!(uri.path().unwrap().as_str(), $res2.3);
1170 assert_eq!(uri.query().unwrap().as_str(), $res2.4);
1171 assert_eq!(uri.to_string(), $res2.5)
1172 }};
1173 }
1174
1175 /// UT test cases for `build_from_builder`.
1176 ///
1177 /// # Brief
1178 /// 1. Creates UriBuilder by calling UriBuilder::new().
1179 /// 2. Sets Scheme by calling scheme().
1180 /// 3. Sets authority by calling authority().
1181 /// 4. Sets path by calling path().
1182 /// 5. Sets query by calling query().
1183 /// 6. Creates Uri by calling build().
1184 /// 7. Gets string slice value of uri components by calling as_str().
1185 /// 8. Gets string value of uri by calling to_string().
1186 /// 9. Checks if the test result is correct by assert_eq!().
1187 #[test]
build_from_builder()1188 fn build_from_builder() {
1189 test_builder_valid!(
1190 ("http", "hyper.rs:80", "/foo", "a=1"),
1191 (
1192 "http",
1193 "hyper.rs",
1194 "80",
1195 "/foo",
1196 "a=1",
1197 "http://hyper.rs:80/foo?a=1"
1198 )
1199 );
1200 test_builder_valid!(
1201 (Scheme::HTTP, "hyper.rs:80", "/foo", "a=1"),
1202 (
1203 "http",
1204 "hyper.rs",
1205 "80",
1206 "/foo",
1207 "a=1",
1208 "http://hyper.rs:80/foo?a=1"
1209 )
1210 );
1211 test_builder_valid!(
1212 ("https", "hyper.rs:80", "/foo", "a=1"),
1213 (
1214 "https",
1215 "hyper.rs",
1216 "80",
1217 "/foo",
1218 "a=1",
1219 "https://hyper.rs:80/foo?a=1"
1220 )
1221 );
1222 test_builder_valid!(
1223 (Scheme::HTTPS, "hyper.rs:80", "/foo", "a=1"),
1224 (
1225 "https",
1226 "hyper.rs",
1227 "80",
1228 "/foo",
1229 "a=1",
1230 "https://hyper.rs:80/foo?a=1"
1231 )
1232 );
1233 }
1234
1235 /// UT test cases for `build_from_instance`.
1236 ///
1237 /// # Brief
1238 /// 1. Creates UriBuilder by calling Uri::builder().
1239 /// 2. Sets Scheme by calling scheme().
1240 /// 3. Sets authority by calling authority().
1241 /// 4. Sets path by calling path().
1242 /// 5. Sets query by calling query().
1243 /// 6. Creates Uri by calling build().
1244 /// 7. Gets string slice value of uri components by calling as_str().
1245 /// 8. Gets string value of uri by calling to_string().
1246 /// 9. Checks if the test result is correct by assert_eq!().
1247 #[test]
build_from_instance()1248 fn build_from_instance() {
1249 let uri = Uri::builder()
1250 .scheme(Scheme::HTTP)
1251 .authority("hyper.rs:80")
1252 .path("/foo")
1253 .query("a=1")
1254 .build()
1255 .unwrap();
1256 assert_eq!(uri.scheme().unwrap().as_str(), "http");
1257 assert_eq!(uri.host().unwrap().as_str(), "hyper.rs");
1258 assert_eq!(uri.port().unwrap().as_str(), "80");
1259 assert_eq!(uri.path().unwrap().as_str(), "/foo");
1260 assert_eq!(uri.query().unwrap().as_str(), "a=1");
1261 assert_eq!(uri.to_string(), "http://hyper.rs:80/foo?a=1")
1262 }
1263
1264 /// UT test cases for `build_from_str`.
1265 ///
1266 /// # Brief
1267 /// 1. Creates Uri by calling from_bytes().
1268 /// 2. Gets string slice value of uri components by calling as_str().
1269 /// 3. Gets u16 value of port by call as_u16().
1270 /// 4. Gets string value of uri by calling to_string().
1271 /// 5. Checks if the test result is correct by assert_eq!().
1272 #[test]
build_from_str()1273 fn build_from_str() {
1274 let uri = Uri::from_bytes("http://hyper.rs:80/foo?a=1".as_bytes()).unwrap();
1275 assert_eq!(uri.scheme().unwrap().as_str(), "http");
1276 assert_eq!(uri.host().unwrap().as_str(), "hyper.rs");
1277 assert_eq!(uri.port().unwrap().as_str(), "80");
1278 assert_eq!(uri.port().unwrap().as_u16().unwrap(), 80);
1279 assert_eq!(uri.path().unwrap().as_str(), "/foo");
1280 assert_eq!(uri.query().unwrap().as_str(), "a=1");
1281 assert_eq!(uri.to_string(), "http://hyper.rs:80/foo?a=1")
1282 }
1283
1284 /// UT test cases for `Uri::from_bytes`.
1285 ///
1286 /// # Brief
1287 /// 1. Creates Uri by calling `Uri::from_bytes()`.
1288 /// 2. Checks if the test results are correct.
1289 #[test]
ut_uri_from_bytes()1290 fn ut_uri_from_bytes() {
1291 macro_rules! uri_test_case {
1292 ($raw: expr, $tar: expr, $(,)?) => {
1293 match (Uri::from_bytes($raw), $tar) {
1294 (Ok(res), Ok(tar)) => assert_eq!(
1295 (
1296 res.scheme().map(|scheme| scheme.as_str()),
1297 res.host().map(|host| host.as_str()),
1298 res.port().map(|port| port.as_str()),
1299 res.path().map(|path| path.as_str()),
1300 res.query().map(|query| query.as_str()),
1301 ),
1302 tar,
1303 ),
1304 (Err(res), Err(tar)) => assert_eq!(res, tar),
1305 _ => panic!("uri test case failed!"),
1306 }
1307 };
1308 }
1309
1310 uri_test_case!(
1311 b"httpss://www.example.com/",
1312 Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidScheme))),
1313 );
1314
1315 uri_test_case!(
1316 b"://www.example.com/",
1317 Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidScheme))),
1318 );
1319
1320 uri_test_case!(
1321 b"https://www.hu awei.com/",
1322 Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1323 );
1324
1325 uri_test_case!(
1326 br#"https://www.hu"awei.com/"#,
1327 Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1328 );
1329
1330 uri_test_case!(
1331 br#"https://www.hu"awei.com/"#,
1332 Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1333 );
1334
1335 uri_test_case!(
1336 br#"https://www.hu"<>\^`awei.com/"#,
1337 Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1338 );
1339
1340 uri_test_case!(
1341 br#"https://www.example.com:a0/"#,
1342 Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidPort))),
1343 );
1344
1345 uri_test_case!(
1346 br#"https://www.example.com:80/message/e<>mail"#,
1347 Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1348 );
1349
1350 uri_test_case!(
1351 br#"https://www.example.com:80/message/email?name='\^'"#,
1352 Err(HttpError::from(ErrorKind::Uri(InvalidUri::InvalidByte))),
1353 );
1354
1355 uri_test_case!(
1356 br#"https:/www.example.com:80/message/email?name=arya"#,
1357 Err(HttpError::from(ErrorKind::Uri(InvalidUri::UriMissScheme))),
1358 );
1359
1360 uri_test_case!(
1361 br#"https:/www.example.com:80"#,
1362 Err(HttpError::from(ErrorKind::Uri(InvalidUri::UriMissScheme))),
1363 );
1364
1365 uri_test_case!(
1366 br#"https:/www.example.com"#,
1367 Err(HttpError::from(ErrorKind::Uri(InvalidUri::UriMissScheme))),
1368 );
1369
1370 uri_test_case!(
1371 br#"https://www.huaw:ei.com:80"#,
1372 Err(HttpError::from(ErrorKind::Uri(
1373 InvalidUri::InvalidAuthority
1374 ))),
1375 );
1376
1377 uri_test_case!(
1378 br#"https://www.huaw:ei.com:80"#,
1379 Err(HttpError::from(ErrorKind::Uri(
1380 InvalidUri::InvalidAuthority
1381 ))),
1382 );
1383
1384 uri_test_case!(
1385 br#"https://name=1234@www.example.com:80/message/email?name=arya"#,
1386 Err(HttpError::from(ErrorKind::Uri(
1387 InvalidUri::UriContainUserinfo
1388 ))),
1389 );
1390
1391 uri_test_case!(
1392 br#"www.example.com:80/message/email?name=arya"#,
1393 Err(HttpError::from(ErrorKind::Uri(InvalidUri::UriMissScheme))),
1394 );
1395
1396 uri_test_case!(
1397 br#"https://[0:0:0:0:0:0:0:0:80/message/email?name=arya"#,
1398 Err(HttpError::from(ErrorKind::Uri(
1399 InvalidUri::InvalidAuthority
1400 ))),
1401 );
1402
1403 uri_test_case!(
1404 br#"https:///foo?a=1"#,
1405 Err(HttpError::from(ErrorKind::Uri(
1406 InvalidUri::UriMissAuthority
1407 ))),
1408 );
1409
1410 uri_test_case!(
1411 b"https://www.example.com/",
1412 Ok((
1413 Some("https"),
1414 Some("www.example.com"),
1415 None,
1416 Some("/"),
1417 None
1418 )),
1419 );
1420
1421 uri_test_case!(
1422 b"https://www.example.com:80/foo?a=1",
1423 Ok((
1424 Some("https"),
1425 Some("www.example.com"),
1426 Some("80"),
1427 Some("/foo"),
1428 Some("a=1"),
1429 )),
1430 );
1431
1432 uri_test_case!(
1433 b"https://www.example.com:80/foo?a=1#fragment",
1434 Ok((
1435 Some("https"),
1436 Some("www.example.com"),
1437 Some("80"),
1438 Some("/foo"),
1439 Some("a=1"),
1440 )),
1441 );
1442
1443 uri_test_case!(
1444 b"https://www.example.com:80?a=1",
1445 Ok((
1446 Some("https"),
1447 Some("www.example.com"),
1448 Some("80"),
1449 None,
1450 Some("a=1"),
1451 )),
1452 );
1453
1454 uri_test_case!(
1455 b"https://www.example.com?a=1",
1456 Ok((
1457 Some("https"),
1458 Some("www.example.com"),
1459 None,
1460 None,
1461 Some("a=1"),
1462 )),
1463 );
1464
1465 uri_test_case!(
1466 b"https://www.example.com?",
1467 Ok((Some("https"), Some("www.example.com"), None, None, None)),
1468 );
1469
1470 uri_test_case!(
1471 b"https://www.example.com:80",
1472 Ok((
1473 Some("https"),
1474 Some("www.example.com"),
1475 Some("80"),
1476 None,
1477 None,
1478 )),
1479 );
1480
1481 uri_test_case!(
1482 b"https://www.example.com",
1483 Ok((Some("https"), Some("www.example.com"), None, None, None)),
1484 );
1485
1486 uri_test_case!(
1487 b"https://www.example.com#fragment",
1488 Ok((Some("https"), Some("www.example.com"), None, None, None)),
1489 );
1490
1491 uri_test_case!(
1492 b"www.example.com",
1493 Ok((None, Some("www.example.com"), None, None, None)),
1494 );
1495
1496 uri_test_case!(
1497 b"/foo?a=1",
1498 Ok((None, None, None, Some("/foo"), Some("a=1"))),
1499 );
1500
1501 uri_test_case!(
1502 b"https://[0:0:0:0:0:0:0:0]",
1503 Ok((Some("https"), Some("[0:0:0:0:0:0:0:0]"), None, None, None)),
1504 );
1505
1506 uri_test_case!(
1507 b"https://[0:0:0:0:0:0:0:0]:80",
1508 Ok((
1509 Some("https"),
1510 Some("[0:0:0:0:0:0:0:0]"),
1511 Some("80"),
1512 None,
1513 None,
1514 )),
1515 );
1516 }
1517
1518 /// UT test cases for `Uri::authority`.
1519 ///
1520 /// # Brief
1521 /// 1. Creates Uri by calling `Uri::authority()`.
1522 /// 2. Checks if the test results are correct.
1523 #[test]
ut_uri_authority()1524 fn ut_uri_authority() {
1525 let uri = Uri::from_bytes(b"http://example.com:8080/foo?a=1").unwrap();
1526 let authority = uri.authority().unwrap();
1527 assert_eq!(authority.host.as_str(), "example.com");
1528 assert_eq!(authority.port().unwrap().as_str(), "8080");
1529 }
1530
1531 /// UT test cases for `Uri::path_and_query`.
1532 ///
1533 /// # Brief
1534 /// 1. Creates Uri by calling `Uri::path_and_query()`.
1535 /// 2. Checks if the test results are correct.
1536 #[test]
ut_uri_path_and_query()1537 fn ut_uri_path_and_query() {
1538 let uri = Uri::from_bytes(b"http://example.com:8080/foo?a=1").unwrap();
1539 assert_eq!(uri.path_and_query().unwrap(), "/foo?a=1");
1540
1541 let uri = Uri::from_bytes(b"http://example.com:8080").unwrap();
1542 assert_eq!(uri.path_and_query(), None);
1543 }
1544 }
1545