Coverage Report

Created: 2025-08-26 07:09

/src/http/src/uri/mod.rs
Line
Count
Source (jump to first uncovered line)
1
//! URI component of request and response lines
2
//!
3
//! This module primarily contains the `Uri` type which is a component of all
4
//! HTTP requests and also reexports this type at the root of the crate. A URI
5
//! is not always a "full URL" in the sense of something you'd type into a web
6
//! browser, but HTTP requests may only have paths on servers but may have full
7
//! schemes and hostnames on clients.
8
//!
9
//! # Examples
10
//!
11
//! ```
12
//! use http::Uri;
13
//!
14
//! let uri = "/foo/bar?baz".parse::<Uri>().unwrap();
15
//! assert_eq!(uri.path(), "/foo/bar");
16
//! assert_eq!(uri.query(), Some("baz"));
17
//! assert_eq!(uri.host(), None);
18
//!
19
//! let uri = "https://www.rust-lang.org/install.html".parse::<Uri>().unwrap();
20
//! assert_eq!(uri.scheme_str(), Some("https"));
21
//! assert_eq!(uri.host(), Some("www.rust-lang.org"));
22
//! assert_eq!(uri.path(), "/install.html");
23
//! ```
24
25
use crate::byte_str::ByteStr;
26
use std::convert::TryFrom;
27
28
use bytes::Bytes;
29
30
use std::error::Error;
31
use std::fmt;
32
use std::hash::{Hash, Hasher};
33
use std::str::{self, FromStr};
34
35
use self::scheme::Scheme2;
36
37
pub use self::authority::Authority;
38
pub use self::builder::Builder;
39
pub use self::path::PathAndQuery;
40
pub use self::port::Port;
41
pub use self::scheme::Scheme;
42
43
mod authority;
44
mod builder;
45
mod path;
46
mod port;
47
mod scheme;
48
#[cfg(test)]
49
mod tests;
50
51
/// The URI component of a request.
52
///
53
/// For HTTP 1, this is included as part of the request line. From Section 5.3,
54
/// Request Target:
55
///
56
/// > Once an inbound connection is obtained, the client sends an HTTP
57
/// > request message (Section 3) with a request-target derived from the
58
/// > target URI.  There are four distinct formats for the request-target,
59
/// > depending on both the method being requested and whether the request
60
/// > is to a proxy.
61
/// >
62
/// > ```notrust
63
/// > request-target = origin-form
64
/// >                / absolute-form
65
/// >                / authority-form
66
/// >                / asterisk-form
67
/// > ```
68
///
69
/// The URI is structured as follows:
70
///
71
/// ```notrust
72
/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
73
/// |-|   |-------------------------------||--------| |-------------------| |-----|
74
///  |                  |                       |               |              |
75
/// scheme          authority                 path            query         fragment
76
/// ```
77
///
78
/// For HTTP 2.0, the URI is encoded using pseudoheaders.
79
///
80
/// # Examples
81
///
82
/// ```
83
/// use http::Uri;
84
///
85
/// let uri = "/foo/bar?baz".parse::<Uri>().unwrap();
86
/// assert_eq!(uri.path(), "/foo/bar");
87
/// assert_eq!(uri.query(), Some("baz"));
88
/// assert_eq!(uri.host(), None);
89
///
90
/// let uri = "https://www.rust-lang.org/install.html".parse::<Uri>().unwrap();
91
/// assert_eq!(uri.scheme_str(), Some("https"));
92
/// assert_eq!(uri.host(), Some("www.rust-lang.org"));
93
/// assert_eq!(uri.path(), "/install.html");
94
/// ```
95
#[derive(Clone)]
96
pub struct Uri {
97
    scheme: Scheme,
98
    authority: Authority,
99
    path_and_query: PathAndQuery,
100
}
101
102
/// The various parts of a URI.
103
///
104
/// This struct is used to provide to and retrieve from a URI.
105
#[derive(Debug, Default)]
106
pub struct Parts {
107
    /// The scheme component of a URI
108
    pub scheme: Option<Scheme>,
109
110
    /// The authority component of a URI
111
    pub authority: Option<Authority>,
112
113
    /// The origin-form component of a URI
114
    pub path_and_query: Option<PathAndQuery>,
115
116
    /// Allow extending in the future
117
    _priv: (),
118
}
119
120
/// An error resulting from a failed attempt to construct a URI.
121
#[derive(Debug)]
122
pub struct InvalidUri(ErrorKind);
123
124
/// An error resulting from a failed attempt to construct a URI.
125
#[derive(Debug)]
126
pub struct InvalidUriParts(InvalidUri);
127
128
#[derive(Debug, Eq, PartialEq)]
129
enum ErrorKind {
130
    InvalidUriChar,
131
    InvalidScheme,
132
    InvalidAuthority,
133
    InvalidPort,
134
    InvalidFormat,
135
    SchemeMissing,
136
    AuthorityMissing,
137
    PathAndQueryMissing,
138
    TooLong,
139
    Empty,
140
    SchemeTooLong,
141
}
142
143
// u16::MAX is reserved for None
144
const MAX_LEN: usize = (u16::MAX - 1) as usize;
145
146
// URI_CHARS is a table of valid characters in a URI. An entry in the table is
147
// 0 for invalid characters. For valid characters the entry is itself (i.e.
148
// the entry for 33 is b'!' because b'!' == 33u8). An important characteristic
149
// of this table is that all entries above 127 are invalid. This makes all of the
150
// valid entries a valid single-byte UTF-8 code point. This means that a slice
151
// of such valid entries is valid UTF-8.
152
#[rustfmt::skip]
153
const URI_CHARS: [u8; 256] = [
154
    //  0      1      2      3      4      5      6      7      8      9
155
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //   x
156
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  1x
157
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, //  2x
158
        0,     0,     0,  b'!',     0,  b'#',  b'$',     0,  b'&', b'\'', //  3x
159
     b'(',  b')',  b'*',  b'+',  b',',  b'-',  b'.',  b'/',  b'0',  b'1', //  4x
160
     b'2',  b'3',  b'4',  b'5',  b'6',  b'7',  b'8',  b'9',  b':',  b';', //  5x
161
        0,  b'=',     0,  b'?',  b'@',  b'A',  b'B',  b'C',  b'D',  b'E', //  6x
162
     b'F',  b'G',  b'H',  b'I',  b'J',  b'K',  b'L',  b'M',  b'N',  b'O', //  7x
163
     b'P',  b'Q',  b'R',  b'S',  b'T',  b'U',  b'V',  b'W',  b'X',  b'Y', //  8x
164
     b'Z',  b'[',     0,  b']',     0,  b'_',     0,  b'a',  b'b',  b'c', //  9x
165
     b'd',  b'e',  b'f',  b'g',  b'h',  b'i',  b'j',  b'k',  b'l',  b'm', // 10x
166
     b'n',  b'o',  b'p',  b'q',  b'r',  b's',  b't',  b'u',  b'v',  b'w', // 11x
167
     b'x',  b'y',  b'z',     0,     0,     0,  b'~',     0,     0,     0, // 12x
168
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 13x
169
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 14x
170
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 15x
171
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 16x
172
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 17x
173
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 18x
174
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 19x
175
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 20x
176
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 21x
177
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 22x
178
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 23x
179
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0, // 24x
180
        0,     0,     0,     0,     0,     0                              // 25x
181
];
182
183
impl Uri {
184
    /// Creates a new builder-style object to manufacture a `Uri`.
185
    ///
186
    /// This method returns an instance of `Builder` which can be usd to
187
    /// create a `Uri`.
188
    ///
189
    /// # Examples
190
    ///
191
    /// ```
192
    /// use http::Uri;
193
    ///
194
    /// let uri = Uri::builder()
195
    ///     .scheme("https")
196
    ///     .authority("hyper.rs")
197
    ///     .path_and_query("/")
198
    ///     .build()
199
    ///     .unwrap();
200
    /// ```
201
0
    pub fn builder() -> Builder {
202
0
        Builder::new()
203
0
    }
204
205
    /// Attempt to convert a `Parts` into a `Uri`.
206
    ///
207
    /// # Examples
208
    ///
209
    /// Relative URI
210
    ///
211
    /// ```
212
    /// # use http::uri::*;
213
    /// let mut parts = Parts::default();
214
    /// parts.path_and_query = Some("/foo".parse().unwrap());
215
    ///
216
    /// let uri = Uri::from_parts(parts).unwrap();
217
    ///
218
    /// assert_eq!(uri.path(), "/foo");
219
    ///
220
    /// assert!(uri.scheme().is_none());
221
    /// assert!(uri.authority().is_none());
222
    /// ```
223
    ///
224
    /// Absolute URI
225
    ///
226
    /// ```
227
    /// # use http::uri::*;
228
    /// let mut parts = Parts::default();
229
    /// parts.scheme = Some("http".parse().unwrap());
230
    /// parts.authority = Some("foo.com".parse().unwrap());
231
    /// parts.path_and_query = Some("/foo".parse().unwrap());
232
    ///
233
    /// let uri = Uri::from_parts(parts).unwrap();
234
    ///
235
    /// assert_eq!(uri.scheme().unwrap().as_str(), "http");
236
    /// assert_eq!(uri.authority().unwrap(), "foo.com");
237
    /// assert_eq!(uri.path(), "/foo");
238
    /// ```
239
0
    pub fn from_parts(src: Parts) -> Result<Uri, InvalidUriParts> {
240
0
        if src.scheme.is_some() {
241
0
            if src.authority.is_none() {
242
0
                return Err(ErrorKind::AuthorityMissing.into());
243
0
            }
244
0
245
0
            if src.path_and_query.is_none() {
246
0
                return Err(ErrorKind::PathAndQueryMissing.into());
247
0
            }
248
0
        } else if src.authority.is_some() && src.path_and_query.is_some() {
249
0
            return Err(ErrorKind::SchemeMissing.into());
250
0
        }
251
252
0
        let scheme = match src.scheme {
253
0
            Some(scheme) => scheme,
254
0
            None => Scheme {
255
0
                inner: Scheme2::None,
256
0
            },
257
        };
258
259
0
        let authority = match src.authority {
260
0
            Some(authority) => authority,
261
0
            None => Authority::empty(),
262
        };
263
264
0
        let path_and_query = match src.path_and_query {
265
0
            Some(path_and_query) => path_and_query,
266
0
            None => PathAndQuery::empty(),
267
        };
268
269
0
        Ok(Uri {
270
0
            scheme,
271
0
            authority,
272
0
            path_and_query,
273
0
        })
274
0
    }
275
276
    /// Attempt to convert a `Bytes` buffer to a `Uri`.
277
    ///
278
    /// This will try to prevent a copy if the type passed is the type used
279
    /// internally, and will copy the data if it is not.
280
0
    pub fn from_maybe_shared<T>(src: T) -> Result<Self, InvalidUri>
281
0
    where
282
0
        T: AsRef<[u8]> + 'static,
283
0
    {
284
0
        if_downcast_into!(T, Bytes, src, {
285
0
            return Uri::from_shared(src);
286
        });
287
288
0
        Uri::try_from(src.as_ref())
289
0
    }
290
291
    // Not public while `bytes` is unstable.
292
5.69k
    fn from_shared(s: Bytes) -> Result<Uri, InvalidUri> {
293
        use self::ErrorKind::*;
294
295
5.69k
        if s.len() > MAX_LEN {
296
13
            return Err(TooLong.into());
297
5.68k
        }
298
5.68k
299
5.68k
        match s.len() {
300
            0 => {
301
3.78k
                return Err(Empty.into());
302
            }
303
1.15k
            1 => match s[0] {
304
                b'/' => {
305
150
                    return Ok(Uri {
306
150
                        scheme: Scheme::empty(),
307
150
                        authority: Authority::empty(),
308
150
                        path_and_query: PathAndQuery::slash(),
309
150
                    });
310
                }
311
                b'*' => {
312
23
                    return Ok(Uri {
313
23
                        scheme: Scheme::empty(),
314
23
                        authority: Authority::empty(),
315
23
                        path_and_query: PathAndQuery::star(),
316
23
                    });
317
                }
318
                _ => {
319
981
                    let authority = Authority::from_shared(s)?;
320
321
947
                    return Ok(Uri {
322
947
                        scheme: Scheme::empty(),
323
947
                        authority,
324
947
                        path_and_query: PathAndQuery::empty(),
325
947
                    });
326
                }
327
            },
328
743
            _ => {}
329
743
        }
330
743
331
743
        if s[0] == b'/' {
332
            return Ok(Uri {
333
291
                scheme: Scheme::empty(),
334
291
                authority: Authority::empty(),
335
291
                path_and_query: PathAndQuery::from_shared(s)?,
336
            });
337
452
        }
338
452
339
452
        parse_full(s)
340
5.69k
    }
341
342
    /// Convert a `Uri` from a static string.
343
    ///
344
    /// This function will not perform any copying, however the string is
345
    /// checked to ensure that it is valid.
346
    ///
347
    /// # Panics
348
    ///
349
    /// This function panics if the argument is an invalid URI.
350
    ///
351
    /// # Examples
352
    ///
353
    /// ```
354
    /// # use http::uri::Uri;
355
    /// let uri = Uri::from_static("http://example.com/foo");
356
    ///
357
    /// assert_eq!(uri.host().unwrap(), "example.com");
358
    /// assert_eq!(uri.path(), "/foo");
359
    /// ```
360
0
    pub fn from_static(src: &'static str) -> Self {
361
0
        let s = Bytes::from_static(src.as_bytes());
362
0
        match Uri::from_shared(s) {
363
0
            Ok(uri) => uri,
364
0
            Err(e) => panic!("static str is not valid URI: {}", e),
365
        }
366
0
    }
367
368
    /// Convert a `Uri` into `Parts`.
369
    ///
370
    /// # Note
371
    ///
372
    /// This is just an inherent method providing the same functionality as
373
    /// `let parts: Parts = uri.into()`
374
    ///
375
    /// # Examples
376
    ///
377
    /// ```
378
    /// # use http::uri::*;
379
    /// let uri: Uri = "/foo".parse().unwrap();
380
    ///
381
    /// let parts = uri.into_parts();
382
    ///
383
    /// assert_eq!(parts.path_and_query.unwrap(), "/foo");
384
    ///
385
    /// assert!(parts.scheme.is_none());
386
    /// assert!(parts.authority.is_none());
387
    /// ```
388
    #[inline]
389
0
    pub fn into_parts(self) -> Parts {
390
0
        self.into()
391
0
    }
392
393
    /// Returns the path & query components of the Uri
394
    #[inline]
395
0
    pub fn path_and_query(&self) -> Option<&PathAndQuery> {
396
0
        if !self.scheme.inner.is_none() || self.authority.data.is_empty() {
397
0
            Some(&self.path_and_query)
398
        } else {
399
0
            None
400
        }
401
0
    }
402
403
    /// Get the path of this `Uri`.
404
    ///
405
    /// Both relative and absolute URIs contain a path component, though it
406
    /// might be the empty string. The path component is **case sensitive**.
407
    ///
408
    /// ```notrust
409
    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
410
    ///                                        |--------|
411
    ///                                             |
412
    ///                                           path
413
    /// ```
414
    ///
415
    /// If the URI is `*` then the path component is equal to `*`.
416
    ///
417
    /// # Examples
418
    ///
419
    /// A relative URI
420
    ///
421
    /// ```
422
    /// # use http::Uri;
423
    ///
424
    /// let uri: Uri = "/hello/world".parse().unwrap();
425
    ///
426
    /// assert_eq!(uri.path(), "/hello/world");
427
    /// ```
428
    ///
429
    /// An absolute URI
430
    ///
431
    /// ```
432
    /// # use http::Uri;
433
    /// let uri: Uri = "http://example.org/hello/world".parse().unwrap();
434
    ///
435
    /// assert_eq!(uri.path(), "/hello/world");
436
    /// ```
437
    #[inline]
438
0
    pub fn path(&self) -> &str {
439
0
        if self.has_path() {
440
0
            self.path_and_query.path()
441
        } else {
442
0
            ""
443
        }
444
0
    }
445
446
    /// Get the scheme of this `Uri`.
447
    ///
448
    /// The URI scheme refers to a specification for assigning identifiers
449
    /// within that scheme. Only absolute URIs contain a scheme component, but
450
    /// not all absolute URIs will contain a scheme component.  Although scheme
451
    /// names are case-insensitive, the canonical form is lowercase.
452
    ///
453
    /// ```notrust
454
    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
455
    /// |-|
456
    ///  |
457
    /// scheme
458
    /// ```
459
    ///
460
    /// # Examples
461
    ///
462
    /// Absolute URI
463
    ///
464
    /// ```
465
    /// use http::uri::{Scheme, Uri};
466
    ///
467
    /// let uri: Uri = "http://example.org/hello/world".parse().unwrap();
468
    ///
469
    /// assert_eq!(uri.scheme(), Some(&Scheme::HTTP));
470
    /// ```
471
    ///
472
    ///
473
    /// Relative URI
474
    ///
475
    /// ```
476
    /// # use http::Uri;
477
    /// let uri: Uri = "/hello/world".parse().unwrap();
478
    ///
479
    /// assert!(uri.scheme().is_none());
480
    /// ```
481
    #[inline]
482
0
    pub fn scheme(&self) -> Option<&Scheme> {
483
0
        if self.scheme.inner.is_none() {
484
0
            None
485
        } else {
486
0
            Some(&self.scheme)
487
        }
488
0
    }
489
490
    /// Get the scheme of this `Uri` as a `&str`.
491
    ///
492
    /// # Example
493
    ///
494
    /// ```
495
    /// # use http::Uri;
496
    /// let uri: Uri = "http://example.org/hello/world".parse().unwrap();
497
    ///
498
    /// assert_eq!(uri.scheme_str(), Some("http"));
499
    /// ```
500
    #[inline]
501
0
    pub fn scheme_str(&self) -> Option<&str> {
502
0
        if self.scheme.inner.is_none() {
503
0
            None
504
        } else {
505
0
            Some(self.scheme.as_str())
506
        }
507
0
    }
508
509
    /// Get the authority of this `Uri`.
510
    ///
511
    /// The authority is a hierarchical element for naming authority such that
512
    /// the remainder of the URI is delegated to that authority. For HTTP, the
513
    /// authority consists of the host and port. The host portion of the
514
    /// authority is **case-insensitive**.
515
    ///
516
    /// The authority also includes a `username:password` component, however
517
    /// the use of this is deprecated and should be avoided.
518
    ///
519
    /// ```notrust
520
    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
521
    ///       |-------------------------------|
522
    ///                     |
523
    ///                 authority
524
    /// ```
525
    ///
526
    /// # Examples
527
    ///
528
    /// Absolute URI
529
    ///
530
    /// ```
531
    /// # use http::Uri;
532
    /// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap();
533
    ///
534
    /// assert_eq!(uri.authority().map(|a| a.as_str()), Some("example.org:80"));
535
    /// ```
536
    ///
537
    ///
538
    /// Relative URI
539
    ///
540
    /// ```
541
    /// # use http::Uri;
542
    /// let uri: Uri = "/hello/world".parse().unwrap();
543
    ///
544
    /// assert!(uri.authority().is_none());
545
    /// ```
546
    #[inline]
547
0
    pub fn authority(&self) -> Option<&Authority> {
548
0
        if self.authority.data.is_empty() {
549
0
            None
550
        } else {
551
0
            Some(&self.authority)
552
        }
553
0
    }
554
555
    /// Get the host of this `Uri`.
556
    ///
557
    /// The host subcomponent of authority is identified by an IP literal
558
    /// encapsulated within square brackets, an IPv4 address in dotted- decimal
559
    /// form, or a registered name.  The host subcomponent is **case-insensitive**.
560
    ///
561
    /// ```notrust
562
    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
563
    ///                         |---------|
564
    ///                              |
565
    ///                             host
566
    /// ```
567
    ///
568
    /// # Examples
569
    ///
570
    /// Absolute URI
571
    ///
572
    /// ```
573
    /// # use http::Uri;
574
    /// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap();
575
    ///
576
    /// assert_eq!(uri.host(), Some("example.org"));
577
    /// ```
578
    ///
579
    ///
580
    /// Relative URI
581
    ///
582
    /// ```
583
    /// # use http::Uri;
584
    /// let uri: Uri = "/hello/world".parse().unwrap();
585
    ///
586
    /// assert!(uri.host().is_none());
587
    /// ```
588
    #[inline]
589
0
    pub fn host(&self) -> Option<&str> {
590
0
        self.authority().map(|a| a.host())
591
0
    }
592
593
    /// Get the port part of this `Uri`.
594
    ///
595
    /// The port subcomponent of authority is designated by an optional port
596
    /// number following the host and delimited from it by a single colon (":")
597
    /// character. It can be turned into a decimal port number with the `as_u16`
598
    /// method or as a `str` with the `as_str` method.
599
    ///
600
    /// ```notrust
601
    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
602
    ///                                     |-|
603
    ///                                      |
604
    ///                                     port
605
    /// ```
606
    ///
607
    /// # Examples
608
    ///
609
    /// Absolute URI with port
610
    ///
611
    /// ```
612
    /// # use http::Uri;
613
    /// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap();
614
    ///
615
    /// let port = uri.port().unwrap();
616
    /// assert_eq!(port.as_u16(), 80);
617
    /// ```
618
    ///
619
    /// Absolute URI without port
620
    ///
621
    /// ```
622
    /// # use http::Uri;
623
    /// let uri: Uri = "http://example.org/hello/world".parse().unwrap();
624
    ///
625
    /// assert!(uri.port().is_none());
626
    /// ```
627
    ///
628
    /// Relative URI
629
    ///
630
    /// ```
631
    /// # use http::Uri;
632
    /// let uri: Uri = "/hello/world".parse().unwrap();
633
    ///
634
    /// assert!(uri.port().is_none());
635
    /// ```
636
0
    pub fn port(&self) -> Option<Port<&str>> {
637
0
        self.authority().and_then(|a| a.port())
638
0
    }
639
640
    /// Get the port of this `Uri` as a `u16`.
641
    ///
642
    ///
643
    /// # Example
644
    ///
645
    /// ```
646
    /// # use http::{Uri, uri::Port};
647
    /// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap();
648
    ///
649
    /// assert_eq!(uri.port_u16(), Some(80));
650
    /// ```
651
0
    pub fn port_u16(&self) -> Option<u16> {
652
0
        self.port().map(|p| p.as_u16())
653
0
    }
654
655
    /// Get the query string of this `Uri`, starting after the `?`.
656
    ///
657
    /// The query component contains non-hierarchical data that, along with data
658
    /// in the path component, serves to identify a resource within the scope of
659
    /// the URI's scheme and naming authority (if any). The query component is
660
    /// indicated by the first question mark ("?") character and terminated by a
661
    /// number sign ("#") character or by the end of the URI.
662
    ///
663
    /// ```notrust
664
    /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
665
    ///                                                   |-------------------|
666
    ///                                                             |
667
    ///                                                           query
668
    /// ```
669
    ///
670
    /// # Examples
671
    ///
672
    /// Absolute URI
673
    ///
674
    /// ```
675
    /// # use http::Uri;
676
    /// let uri: Uri = "http://example.org/hello/world?key=value".parse().unwrap();
677
    ///
678
    /// assert_eq!(uri.query(), Some("key=value"));
679
    /// ```
680
    ///
681
    /// Relative URI with a query string component
682
    ///
683
    /// ```
684
    /// # use http::Uri;
685
    /// let uri: Uri = "/hello/world?key=value&foo=bar".parse().unwrap();
686
    ///
687
    /// assert_eq!(uri.query(), Some("key=value&foo=bar"));
688
    /// ```
689
    ///
690
    /// Relative URI without a query string component
691
    ///
692
    /// ```
693
    /// # use http::Uri;
694
    /// let uri: Uri = "/hello/world".parse().unwrap();
695
    ///
696
    /// assert!(uri.query().is_none());
697
    /// ```
698
    #[inline]
699
0
    pub fn query(&self) -> Option<&str> {
700
0
        self.path_and_query.query()
701
0
    }
702
703
0
    fn has_path(&self) -> bool {
704
0
        !self.path_and_query.data.is_empty() || !self.scheme.inner.is_none()
705
0
    }
706
}
707
708
impl<'a> TryFrom<&'a [u8]> for Uri {
709
    type Error = InvalidUri;
710
711
    #[inline]
712
5.69k
    fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
713
5.69k
        Uri::from_shared(Bytes::copy_from_slice(t))
714
5.69k
    }
<http::uri::Uri as core::convert::TryFrom<&[u8]>>::try_from
Line
Count
Source
712
5.69k
    fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
713
5.69k
        Uri::from_shared(Bytes::copy_from_slice(t))
714
5.69k
    }
Unexecuted instantiation: <http::uri::Uri as core::convert::TryFrom<&[u8]>>::try_from
715
}
716
717
impl<'a> TryFrom<&'a str> for Uri {
718
    type Error = InvalidUri;
719
720
    #[inline]
721
0
    fn try_from(t: &'a str) -> Result<Self, Self::Error> {
722
0
        t.parse()
723
0
    }
724
}
725
726
impl<'a> TryFrom<&'a String> for Uri {
727
    type Error = InvalidUri;
728
729
    #[inline]
730
0
    fn try_from(t: &'a String) -> Result<Self, Self::Error> {
731
0
        t.parse()
732
0
    }
733
}
734
735
impl TryFrom<String> for Uri {
736
    type Error = InvalidUri;
737
738
    #[inline]
739
0
    fn try_from(t: String) -> Result<Self, Self::Error> {
740
0
        Uri::from_shared(Bytes::from(t))
741
0
    }
742
}
743
744
impl TryFrom<Vec<u8>> for Uri {
745
    type Error = InvalidUri;
746
747
    #[inline]
748
0
    fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
749
0
        Uri::from_shared(Bytes::from(vec))
750
0
    }
751
}
752
753
impl TryFrom<Parts> for Uri {
754
    type Error = InvalidUriParts;
755
756
    #[inline]
757
0
    fn try_from(src: Parts) -> Result<Self, Self::Error> {
758
0
        Uri::from_parts(src)
759
0
    }
760
}
761
762
impl<'a> TryFrom<&'a Uri> for Uri {
763
    type Error = crate::Error;
764
765
    #[inline]
766
0
    fn try_from(src: &'a Uri) -> Result<Self, Self::Error> {
767
0
        Ok(src.clone())
768
0
    }
769
}
770
771
/// Convert an `Authority` into a `Uri`.
772
impl From<Authority> for Uri {
773
0
    fn from(authority: Authority) -> Self {
774
0
        Self {
775
0
            scheme: Scheme::empty(),
776
0
            authority,
777
0
            path_and_query: PathAndQuery::empty(),
778
0
        }
779
0
    }
780
}
781
782
/// Convert a `PathAndQuery` into a `Uri`.
783
impl From<PathAndQuery> for Uri {
784
0
    fn from(path_and_query: PathAndQuery) -> Self {
785
0
        Self {
786
0
            scheme: Scheme::empty(),
787
0
            authority: Authority::empty(),
788
0
            path_and_query,
789
0
        }
790
0
    }
791
}
792
793
/// Convert a `Uri` into `Parts`
794
impl From<Uri> for Parts {
795
0
    fn from(src: Uri) -> Self {
796
0
        let path_and_query = if src.has_path() {
797
0
            Some(src.path_and_query)
798
        } else {
799
0
            None
800
        };
801
802
0
        let scheme = match src.scheme.inner {
803
0
            Scheme2::None => None,
804
0
            _ => Some(src.scheme),
805
        };
806
807
0
        let authority = if src.authority.data.is_empty() {
808
0
            None
809
        } else {
810
0
            Some(src.authority)
811
        };
812
813
0
        Parts {
814
0
            scheme,
815
0
            authority,
816
0
            path_and_query,
817
0
            _priv: (),
818
0
        }
819
0
    }
820
}
821
822
452
fn parse_full(mut s: Bytes) -> Result<Uri, InvalidUri> {
823
    // Parse the scheme
824
452
    let scheme = match Scheme2::parse(&s[..])? {
825
351
        Scheme2::None => Scheme2::None,
826
5
        Scheme2::Standard(p) => {
827
5
            // TODO: use truncate
828
5
            let _ = s.split_to(p.len() + 3);
829
5
            Scheme2::Standard(p)
830
        }
831
82
        Scheme2::Other(n) => {
832
82
            // Grab the protocol
833
82
            let mut scheme = s.split_to(n + 3);
834
82
835
82
            // Strip ://, TODO: truncate
836
82
            let _ = scheme.split_off(n);
837
82
838
82
            // Allocate the ByteStr
839
82
            let val = unsafe { ByteStr::from_utf8_unchecked(scheme) };
840
82
841
82
            Scheme2::Other(Box::new(val))
842
        }
843
    };
844
845
    // Find the end of the authority. The scheme will already have been
846
    // extracted.
847
438
    let authority_end = Authority::parse(&s[..])?;
848
849
151
    if scheme.is_none() {
850
87
        if authority_end != s.len() {
851
56
            return Err(ErrorKind::InvalidFormat.into());
852
31
        }
853
31
854
31
        let authority = Authority {
855
31
            data: unsafe { ByteStr::from_utf8_unchecked(s) },
856
31
        };
857
31
858
31
        return Ok(Uri {
859
31
            scheme: scheme.into(),
860
31
            authority,
861
31
            path_and_query: PathAndQuery::empty(),
862
31
        });
863
64
    }
864
64
865
64
    // Authority is required when absolute
866
64
    if authority_end == 0 {
867
4
        return Err(ErrorKind::InvalidFormat.into());
868
60
    }
869
60
870
60
    let authority = s.split_to(authority_end);
871
60
    let authority = Authority {
872
60
        data: unsafe { ByteStr::from_utf8_unchecked(authority) },
873
60
    };
874
60
875
60
    Ok(Uri {
876
60
        scheme: scheme.into(),
877
60
        authority,
878
60
        path_and_query: PathAndQuery::from_shared(s)?,
879
    })
880
452
}
881
882
impl FromStr for Uri {
883
    type Err = InvalidUri;
884
885
    #[inline]
886
0
    fn from_str(s: &str) -> Result<Uri, InvalidUri> {
887
0
        Uri::try_from(s.as_bytes())
888
0
    }
889
}
890
891
impl PartialEq for Uri {
892
0
    fn eq(&self, other: &Uri) -> bool {
893
0
        if self.scheme() != other.scheme() {
894
0
            return false;
895
0
        }
896
0
897
0
        if self.authority() != other.authority() {
898
0
            return false;
899
0
        }
900
0
901
0
        if self.path() != other.path() {
902
0
            return false;
903
0
        }
904
0
905
0
        if self.query() != other.query() {
906
0
            return false;
907
0
        }
908
0
909
0
        true
910
0
    }
911
}
912
913
impl PartialEq<str> for Uri {
914
0
    fn eq(&self, other: &str) -> bool {
915
0
        let mut other = other.as_bytes();
916
0
        let mut absolute = false;
917
918
0
        if let Some(scheme) = self.scheme() {
919
0
            let scheme = scheme.as_str().as_bytes();
920
0
            absolute = true;
921
0
922
0
            if other.len() < scheme.len() + 3 {
923
0
                return false;
924
0
            }
925
0
926
0
            if !scheme.eq_ignore_ascii_case(&other[..scheme.len()]) {
927
0
                return false;
928
0
            }
929
0
930
0
            other = &other[scheme.len()..];
931
0
932
0
            if &other[..3] != b"://" {
933
0
                return false;
934
0
            }
935
0
936
0
            other = &other[3..];
937
0
        }
938
939
0
        if let Some(auth) = self.authority() {
940
0
            let len = auth.data.len();
941
0
            absolute = true;
942
0
943
0
            if other.len() < len {
944
0
                return false;
945
0
            }
946
0
947
0
            if !auth.data.as_bytes().eq_ignore_ascii_case(&other[..len]) {
948
0
                return false;
949
0
            }
950
0
951
0
            other = &other[len..];
952
0
        }
953
954
0
        let path = self.path();
955
0
956
0
        if other.len() < path.len() || path.as_bytes() != &other[..path.len()] {
957
0
            if absolute && path == "/" {
958
0
                // PathAndQuery can be omitted, fall through
959
0
            } else {
960
0
                return false;
961
            }
962
0
        } else {
963
0
            other = &other[path.len()..];
964
0
        }
965
966
0
        if let Some(query) = self.query() {
967
0
            if other.is_empty() {
968
0
                return query.is_empty();
969
0
            }
970
0
971
0
            if other[0] != b'?' {
972
0
                return false;
973
0
            }
974
0
975
0
            other = &other[1..];
976
0
977
0
            if other.len() < query.len() {
978
0
                return false;
979
0
            }
980
0
981
0
            if query.as_bytes() != &other[..query.len()] {
982
0
                return false;
983
0
            }
984
0
985
0
            other = &other[query.len()..];
986
0
        }
987
988
0
        other.is_empty() || other[0] == b'#'
989
0
    }
990
}
991
992
impl PartialEq<Uri> for str {
993
0
    fn eq(&self, uri: &Uri) -> bool {
994
0
        uri == self
995
0
    }
996
}
997
998
impl<'a> PartialEq<&'a str> for Uri {
999
0
    fn eq(&self, other: &&'a str) -> bool {
1000
0
        self == *other
1001
0
    }
1002
}
1003
1004
impl<'a> PartialEq<Uri> for &'a str {
1005
0
    fn eq(&self, uri: &Uri) -> bool {
1006
0
        uri == *self
1007
0
    }
1008
}
1009
1010
impl Eq for Uri {}
1011
1012
/// Returns a `Uri` representing `/`
1013
impl Default for Uri {
1014
    #[inline]
1015
5.69k
    fn default() -> Uri {
1016
5.69k
        Uri {
1017
5.69k
            scheme: Scheme::empty(),
1018
5.69k
            authority: Authority::empty(),
1019
5.69k
            path_and_query: PathAndQuery::slash(),
1020
5.69k
        }
1021
5.69k
    }
1022
}
1023
1024
impl fmt::Display for Uri {
1025
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1026
0
        if let Some(scheme) = self.scheme() {
1027
0
            write!(f, "{}://", scheme)?;
1028
0
        }
1029
1030
0
        if let Some(authority) = self.authority() {
1031
0
            write!(f, "{}", authority)?;
1032
0
        }
1033
1034
0
        write!(f, "{}", self.path())?;
1035
1036
0
        if let Some(query) = self.query() {
1037
0
            write!(f, "?{}", query)?;
1038
0
        }
1039
1040
0
        Ok(())
1041
0
    }
1042
}
1043
1044
impl fmt::Debug for Uri {
1045
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1046
0
        fmt::Display::fmt(self, f)
1047
0
    }
1048
}
1049
1050
impl From<ErrorKind> for InvalidUri {
1051
4.35k
    fn from(src: ErrorKind) -> InvalidUri {
1052
4.35k
        InvalidUri(src)
1053
4.35k
    }
1054
}
1055
1056
impl From<ErrorKind> for InvalidUriParts {
1057
0
    fn from(src: ErrorKind) -> InvalidUriParts {
1058
0
        InvalidUriParts(src.into())
1059
0
    }
1060
}
1061
1062
impl InvalidUri {
1063
0
    fn s(&self) -> &str {
1064
0
        match self.0 {
1065
0
            ErrorKind::InvalidUriChar => "invalid uri character",
1066
0
            ErrorKind::InvalidScheme => "invalid scheme",
1067
0
            ErrorKind::InvalidAuthority => "invalid authority",
1068
0
            ErrorKind::InvalidPort => "invalid port",
1069
0
            ErrorKind::InvalidFormat => "invalid format",
1070
0
            ErrorKind::SchemeMissing => "scheme missing",
1071
0
            ErrorKind::AuthorityMissing => "authority missing",
1072
0
            ErrorKind::PathAndQueryMissing => "path missing",
1073
0
            ErrorKind::TooLong => "uri too long",
1074
0
            ErrorKind::Empty => "empty string",
1075
0
            ErrorKind::SchemeTooLong => "scheme too long",
1076
        }
1077
0
    }
1078
}
1079
1080
impl fmt::Display for InvalidUri {
1081
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1082
0
        self.s().fmt(f)
1083
0
    }
1084
}
1085
1086
impl Error for InvalidUri {}
1087
1088
impl fmt::Display for InvalidUriParts {
1089
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1090
0
        self.0.fmt(f)
1091
0
    }
1092
}
1093
1094
impl Error for InvalidUriParts {}
1095
1096
impl Hash for Uri {
1097
0
    fn hash<H>(&self, state: &mut H)
1098
0
    where
1099
0
        H: Hasher,
1100
0
    {
1101
0
        if !self.scheme.inner.is_none() {
1102
0
            self.scheme.hash(state);
1103
0
            state.write_u8(0xff);
1104
0
        }
1105
1106
0
        if let Some(auth) = self.authority() {
1107
0
            auth.hash(state);
1108
0
        }
1109
1110
0
        Hash::hash_slice(self.path().as_bytes(), state);
1111
1112
0
        if let Some(query) = self.query() {
1113
0
            b'?'.hash(state);
1114
0
            Hash::hash_slice(query.as_bytes(), state);
1115
0
        }
1116
0
    }
1117
}