1 use std::error::Error as StdError;
2 use std::fmt::{Display, self};
3 use std::str::{self, FromStr};
4 
5 #[cfg(feature = "compat")]
6 use http;
7 
8 use ::common::ByteStr;
9 use bytes::{BufMut, Bytes, BytesMut};
10 
11 /// The Request-URI of a Request's StartLine.
12 ///
13 /// From Section 5.3, Request Target:
14 /// > Once an inbound connection is obtained, the client sends an HTTP
15 /// > request message (Section 3) with a request-target derived from the
16 /// > target URI.  There are four distinct formats for the request-target,
17 /// > depending on both the method being requested and whether the request
18 /// > is to a proxy.
19 /// >
20 /// > ```notrust
21 /// > request-target = origin-form
22 /// >                / absolute-form
23 /// >                / authority-form
24 /// >                / asterisk-form
25 /// > ```
26 ///
27 /// # Uri explanations
28 /// ```notrust
29 /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
30 /// |-|   |-------------------------------||--------| |-------------------| |-----|
31 ///  |                  |                       |               |              |
32 /// scheme          authority                 path            query         fragment
33 /// ```
34 #[derive(Clone, Hash)]
35 pub struct Uri {
36     source: ByteStr,
37     scheme_end: Option<usize>,
38     authority_end: Option<usize>,
39     query_start: Option<usize>,
40     fragment_start: Option<usize>,
41 }
42 
43 impl Uri {
44     /// Parse a string into a `Uri`.
new(mut s: ByteStr) -> Result<Uri, UriError>45     fn new(mut s: ByteStr) -> Result<Uri, UriError> {
46         if s.len() == 0 {
47             Err(UriError(ErrorKind::Empty))
48         } else if s.as_bytes() == b"*" {
49             // asterisk-form
50             Ok(asterisk_form())
51         } else if s.as_bytes() == b"/" {
52             // shortcut for '/'
53             Ok(Uri::default())
54         } else if s.as_bytes()[0] == b'/' {
55             // origin-form
56             let query = parse_query(&s);
57             let fragment = parse_fragment(&s);
58             Ok(Uri {
59                 source: s,
60                 scheme_end: None,
61                 authority_end: None,
62                 query_start: query,
63                 fragment_start: fragment,
64             })
65         } else if s.contains("://") {
66             // absolute-form
67             let scheme = parse_scheme(&s);
68             let auth = Some(parse_authority(&s));
69             let scheme_end = scheme.expect("just checked for ':' above");
70             let auth_end = auth.expect("just checked for ://");
71             if scheme_end + 3 == auth_end {
72                 // authority was empty
73                 return Err(UriError(ErrorKind::MissingAuthority));
74             }
75             {
76                 let authority = &s.as_bytes()[scheme_end + 3..auth_end];
77                 let has_start_bracket = authority.contains(&b'[');
78                 let has_end_bracket = authority.contains(&b']');
79                 if has_start_bracket ^ has_end_bracket {
80                     // has only 1 of [ and ]
81                     return Err(UriError(ErrorKind::Malformed));
82                 }
83             }
84 
85             // absolute-form must always have a path
86             // if there isn't a '/', for consistency, add one.
87             let slash = auth_end;
88             if s.len() == slash {
89                 s.insert(slash, '/');
90             } else if s.as_bytes()[slash] != b'/' {
91                 s.insert(slash, '/');
92             }
93 
94             let query = parse_query(&s);
95             let fragment = parse_fragment(&s);
96 
97             Ok(Uri {
98                 source: s,
99                 scheme_end: scheme,
100                 authority_end: auth,
101                 query_start: query,
102                 fragment_start: fragment,
103             })
104         } else if s.contains("/") || s.contains("?") {
105             // last possibility is authority-form, above are illegal characters
106             Err(UriError(ErrorKind::Malformed))
107         } else {
108             // authority-form
109             let len = s.len();
110             Ok(Uri {
111                 source: s,
112                 scheme_end: None,
113                 authority_end: Some(len),
114                 query_start: None,
115                 fragment_start: None,
116             })
117         }
118     }
119 
120     /// Get the path of this `Uri`.
121     #[inline]
path(&self) -> &str122     pub fn path(&self) -> &str {
123         let index = self.path_start();
124         let end = self.path_end();
125         if index >= end {
126             if self.scheme().is_some() {
127                 "/" // absolute-form MUST have path
128             } else {
129                 ""
130             }
131         } else {
132             &self.source[index..end]
133         }
134     }
135 
136     #[inline]
path_start(&self) -> usize137     fn path_start(&self) -> usize {
138         self.authority_end.unwrap_or(self.scheme_end.unwrap_or(0))
139     }
140 
141     #[inline]
path_end(&self) -> usize142     fn path_end(&self) -> usize {
143         if let Some(query) = self.query_start {
144             query
145         } else if let Some(fragment) = self.fragment_start {
146             fragment
147         } else {
148             self.source.len()
149         }
150     }
151 
152     #[inline]
origin_form_end(&self) -> usize153     fn origin_form_end(&self) -> usize {
154         if let Some(fragment) = self.fragment_start {
155             fragment
156         } else {
157             self.source.len()
158         }
159     }
160 
161     /// Get the scheme of this `Uri`.
162     #[inline]
scheme(&self) -> Option<&str>163     pub fn scheme(&self) -> Option<&str> {
164         if let Some(end) = self.scheme_end {
165             Some(&self.source[..end])
166         } else {
167             None
168         }
169     }
170 
171     /// Get the authority of this `Uri`.
172     #[inline]
authority(&self) -> Option<&str>173     pub fn authority(&self) -> Option<&str> {
174         if let Some(end) = self.authority_end {
175             let index = self.scheme_end.map(|i| i + 3).unwrap_or(0);
176 
177             Some(&self.source[index..end])
178         } else {
179             None
180         }
181     }
182 
183     /// Get the host of this `Uri`.
184     #[inline]
host(&self) -> Option<&str>185     pub fn host(&self) -> Option<&str> {
186         self.authority().map(|auth| {
187             let host_port = auth.rsplit('@')
188                 .next()
189                 .expect("split always has at least 1 item");
190             if host_port.as_bytes()[0] == b'[' {
191                 let i = host_port.find(']')
192                     .expect("parsing should validate matching brackets");
193                 &host_port[1..i]
194             } else {
195                 host_port.split(':')
196                     .next()
197                     .expect("split always has at least 1 item")
198             }
199         })
200     }
201 
202     /// Get the port of this `Uri`.
203     #[inline]
port(&self) -> Option<u16>204     pub fn port(&self) -> Option<u16> {
205         match self.authority() {
206             Some(auth) => auth.rfind(':').and_then(|i| auth[i+1..].parse().ok()),
207             None => None,
208        }
209     }
210 
211     /// Get the query string of this `Uri`, starting after the `?`.
212     #[inline]
query(&self) -> Option<&str>213     pub fn query(&self) -> Option<&str> {
214         self.query_start.map(|start| {
215             // +1 to remove '?'
216             let start = start + 1;
217             if let Some(end) = self.fragment_start {
218                 &self.source[start..end]
219             } else {
220                 &self.source[start..]
221             }
222         })
223     }
224 
225     /// Returns whether this URI is in `absolute-form`.
226     ///
227     /// An example of absolute form is `https://hyper.rs`.
228     #[inline]
is_absolute(&self) -> bool229     pub fn is_absolute(&self) -> bool {
230         self.scheme_end.is_some()
231     }
232 
233     #[cfg(test)]
fragment(&self) -> Option<&str>234     fn fragment(&self) -> Option<&str> {
235         self.fragment_start.map(|start| {
236             // +1 to remove the '#'
237            &self.source[start + 1..]
238         })
239     }
240 
241     #[doc(hidden)]
__internal_from_utf8_unchecked(slice: Bytes) -> Result<Uri, UriError>242     pub unsafe fn __internal_from_utf8_unchecked(slice: Bytes) -> Result<Uri, UriError> {
243         Uri::new(ByteStr::from_utf8_unchecked(slice))
244     }
245 
246     #[doc(hidden)]
__internal_scheme_and_authority(&self) -> Option<Uri>247     pub fn __internal_scheme_and_authority(&self) -> Option<Uri> {
248         let uri = self;
249         if uri.scheme_end.is_some() {
250             Some(Uri {
251                 source: uri.source.slice_to(uri.authority_end.expect("scheme without authority")),
252                 scheme_end: uri.scheme_end,
253                 authority_end: uri.authority_end,
254                 query_start: None,
255                 fragment_start: None,
256             })
257         } else {
258             None
259         }
260     }
261 
262     #[doc(hidden)]
__internal_origin_form(&self) -> Uri263     pub fn __internal_origin_form(&self) -> Uri {
264         let uri = self;
265         let range = Range(uri.path_start(), uri.origin_form_end());
266 
267         let clone = if range.len() == 0 {
268             ByteStr::from_static("/")
269         } else if uri.source.as_bytes()[range.0] == b'*' {
270             return asterisk_form();
271         } else if uri.source.as_bytes()[range.0] != b'/' {
272             let mut new = BytesMut::with_capacity(range.1 - range.0 + 1);
273             new.put_u8(b'/');
274             new.put_slice(&uri.source.as_bytes()[range.0..range.1]);
275             // safety: the bytes are '/' + previous utf8 str
276             unsafe { ByteStr::from_utf8_unchecked(new.freeze()) }
277         } else if range.0 == 0 && range.1 == uri.source.len() {
278             uri.source.clone()
279         } else {
280             uri.source.slice(range.0, range.1)
281         };
282 
283         Uri {
284             source: clone,
285             scheme_end: None,
286             authority_end: None,
287             query_start: uri.query_start,
288             fragment_start: None,
289         }
290     }
291 }
292 
parse_scheme(s: &str) -> Option<usize>293 fn parse_scheme(s: &str) -> Option<usize> {
294     s.find(':')
295 }
296 
parse_authority(s: &str) -> usize297 fn parse_authority(s: &str) -> usize {
298     let i = s.find("://").map(|p| p + 3).unwrap_or(0);
299     s[i..]
300         .find(|ch| ch == '/' || ch == '?' || ch == '#')
301         .map(|end| end + i)
302         .unwrap_or(s.len())
303 }
304 
parse_query(s: &str) -> Option<usize>305 fn parse_query(s: &str) -> Option<usize> {
306     s.find('?').and_then(|i| {
307         if let Some(frag) = s.find('#') {
308             if frag < i {
309                 None
310             } else {
311                 Some(i)
312             }
313         } else {
314             Some(i)
315         }
316     })
317 }
318 
parse_fragment(s: &str) -> Option<usize>319 fn parse_fragment(s: &str) -> Option<usize> {
320     s.find('#')
321 }
322 
323 impl FromStr for Uri {
324     type Err = UriError;
325 
from_str(s: &str) -> Result<Uri, UriError>326     fn from_str(s: &str) -> Result<Uri, UriError> {
327         //TODO: refactor such that the to_owned() is only required at the end
328         //of successful parsing, so an Err doesn't needlessly clone the string.
329         Uri::new(ByteStr::from(s))
330     }
331 }
332 
333 impl PartialEq for Uri {
eq(&self, other: &Uri) -> bool334     fn eq(&self, other: &Uri) -> bool {
335         self.source.as_str() == other.source.as_str()
336     }
337 }
338 
339 impl PartialEq<str> for Uri {
eq(&self, other: &str) -> bool340     fn eq(&self, other: &str) -> bool {
341         self.source.as_str() == other
342     }
343 }
344 
345 // FIXME delete for 0.12
346 impl<'a> PartialEq<&'a str> for Uri {
eq(&self, other: & &'a str) -> bool347     fn eq(&self, other: & &'a str) -> bool {
348         self.source.as_str() == *other
349     }
350 }
351 
352 impl<'a> PartialEq<Uri> for &'a str{
eq(&self, other: &Uri) -> bool353     fn eq(&self, other: &Uri) -> bool {
354         *self == other.source.as_str()
355     }
356 }
357 
358 impl Eq for Uri {}
359 
360 impl AsRef<str> for Uri {
as_ref(&self) -> &str361     fn as_ref(&self) -> &str {
362         self.source.as_str()
363     }
364 }
365 
366 impl Default for Uri {
default() -> Uri367     fn default() -> Uri {
368         Uri {
369             source: ByteStr::from_static("/"),
370             scheme_end: None,
371             authority_end: None,
372             query_start: None,
373             fragment_start: None,
374         }
375     }
376 }
377 
378 impl fmt::Debug for Uri {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result379     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
380         fmt::Debug::fmt(self.as_ref(), f)
381     }
382 }
383 
384 impl Display for Uri {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result385     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
386         f.write_str(self.as_ref())
387     }
388 }
389 
390 #[cfg(feature = "compat")]
391 impl From<http::Uri> for Uri {
from(uri: http::Uri) -> Uri392     fn from(uri: http::Uri) -> Uri {
393         uri.to_string().parse()
394             .expect("attempted to convert invalid uri")
395     }
396 }
397 
398 #[cfg(feature = "compat")]
399 impl From<Uri> for http::Uri {
from(uri: Uri) -> http::Uri400     fn from(uri: Uri) -> http::Uri {
401         let bytes = uri.source.into_bytes();
402         http::Uri::from_shared(bytes)
403             .expect("attempted to convert invalid uri")
404     }
405 }
406 
407 
408 #[inline]
asterisk_form() -> Uri409 fn asterisk_form() -> Uri {
410     Uri {
411         source: ByteStr::from_static("*"),
412         scheme_end: None,
413         authority_end: None,
414         query_start: None,
415         fragment_start: None,
416     }
417 }
418 
419 
420 struct Range(usize, usize);
421 
422 impl Range {
len(&self) -> usize423     fn len(&self) -> usize {
424         self.1 - self.0
425     }
426 }
427 
428 /// An error parsing a `Uri`.
429 #[derive(Clone, Debug)]
430 pub struct UriError(ErrorKind);
431 
432 #[derive(Clone, Debug)]
433 enum ErrorKind {
434     Empty,
435     Malformed,
436     MissingAuthority,
437 }
438 
439 impl fmt::Display for UriError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result440     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
441         f.pad(self.description())
442     }
443 }
444 
445 impl StdError for UriError {
description(&self) -> &str446     fn description(&self) -> &str {
447         match self.0 {
448             ErrorKind::Empty => "empty Uri string",
449             ErrorKind::Malformed => "invalid character in Uri authority",
450             ErrorKind::MissingAuthority => "absolute Uri missing authority segment",
451         }
452     }
453 }
454 
455 macro_rules! test_parse {
456     (
457         $test_name:ident,
458         $str:expr,
459         $($method:ident = $value:expr,)*
460     ) => (
461         #[test]
462         fn $test_name() {
463             let uri = Uri::from_str($str).unwrap();
464             $(
465             assert_eq!(uri.$method(), $value, stringify!($method));
466             )+
467         }
468     );
469 }
470 
471 test_parse! {
472     test_uri_parse_origin_form,
473     "/some/path/here?and=then&hello#and-bye",
474 
475     scheme = None,
476     authority = None,
477     path = "/some/path/here",
478     query = Some("and=then&hello"),
479     fragment = Some("and-bye"),
480 }
481 
482 test_parse! {
483     test_uri_parse_absolute_form,
484     "http://127.0.0.1:61761/chunks",
485 
486     scheme = Some("http"),
487     authority = Some("127.0.0.1:61761"),
488     host = Some("127.0.0.1"),
489     path = "/chunks",
490     query = None,
491     fragment = None,
492     port = Some(61761),
493 }
494 
495 test_parse! {
496     test_uri_parse_absolute_form_without_path,
497     "https://127.0.0.1:61761",
498 
499     scheme = Some("https"),
500     authority = Some("127.0.0.1:61761"),
501     host = Some("127.0.0.1"),
502     path = "/",
503     query = None,
504     fragment = None,
505     port = Some(61761),
506 
507     to_string = "https://127.0.0.1:61761/",
508 }
509 
510 test_parse! {
511     test_uri_parse_asterisk_form,
512     "*",
513 
514     scheme = None,
515     authority = None,
516     path = "*",
517     query = None,
518     fragment = None,
519 
520     to_string = "*",
521 }
522 
523 test_parse! {
524     test_uri_parse_authority_no_port,
525     "localhost",
526 
527     scheme = None,
528     authority = Some("localhost"),
529     host = Some("localhost"),
530     path = "",
531     query = None,
532     fragment = None,
533     port = None,
534 
535     to_string = "localhost",
536 }
537 
538 test_parse! {
539     test_uri_parse_authority_form,
540     "localhost:3000",
541 
542     scheme = None,
543     authority = Some("localhost:3000"),
544     host = Some("localhost"),
545     path = "",
546     query = None,
547     fragment = None,
548     port = Some(3000),
549 }
550 
551 test_parse! {
552     test_uri_parse_absolute_with_default_port_http,
553     "http://127.0.0.1:80/foo",
554 
555     scheme = Some("http"),
556     authority = Some("127.0.0.1:80"),
557     host = Some("127.0.0.1"),
558     path = "/foo",
559     query = None,
560     fragment = None,
561     port = Some(80),
562 }
563 
564 test_parse! {
565     test_uri_parse_absolute_with_default_port_https,
566     "https://127.0.0.1:443",
567 
568     scheme = Some("https"),
569     authority = Some("127.0.0.1:443"),
570     host = Some("127.0.0.1"),
571     path = "/",
572     query = None,
573     fragment = None,
574     port = Some(443),
575 }
576 
577 test_parse! {
578     test_uri_parse_absolute_with_ipv6,
579     "https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8008",
580 
581     scheme = Some("https"),
582     authority = Some("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8008"),
583     host = Some("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
584     path = "/",
585     query = None,
586     fragment = None,
587     port = Some(8008),
588 }
589 
590 test_parse! {
591     test_uri_parse_absolute_with_ipv6_and_no_port,
592     "https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]",
593 
594     scheme = Some("https"),
595     authority = Some("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"),
596     host = Some("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
597     path = "/",
598     query = None,
599     fragment = None,
600     port = None,
601 }
602 
603 test_parse! {
604     test_uri_parse_absolute_with_userinfo,
605     "https://seanmonstar:password@hyper.rs",
606 
607     scheme = Some("https"),
608     authority = Some("seanmonstar:password@hyper.rs"),
609     host = Some("hyper.rs"),
610     path = "/",
611     query = None,
612     fragment = None,
613     port = None,
614 }
615 
616 test_parse! {
617     test_uri_parse_fragment_questionmark,
618     "http://127.0.0.1/#?",
619 
620     scheme = Some("http"),
621     authority = Some("127.0.0.1"),
622     host = Some("127.0.0.1"),
623     path = "/",
624     query = None,
625     fragment = Some("?"),
626     port = None,
627 }
628 
629 test_parse! {
630     test_uri_parse_path_with_terminating_questionmark,
631     "http://127.0.0.1/path?",
632 
633     scheme = Some("http"),
634     authority = Some("127.0.0.1"),
635     host = Some("127.0.0.1"),
636     path = "/path",
637     query = Some(""),
638     fragment = None,
639     port = None,
640 }
641 
642 test_parse! {
643     test_uri_parse_absolute_form_with_empty_path_and_nonempty_query,
644     "http://127.0.0.1?foo=bar",
645 
646     scheme = Some("http"),
647     authority = Some("127.0.0.1"),
648     host = Some("127.0.0.1"),
649     path = "/",
650     query = Some("foo=bar"),
651     fragment = None,
652     port = None,
653 
654     to_string = "http://127.0.0.1/?foo=bar",
655 }
656 
657 test_parse! {
658     test_uri_parse_absolute_form_with_empty_path_and_fragment_with_slash,
659     "http://127.0.0.1#foo/bar",
660     scheme = Some("http"),
661     authority = Some("127.0.0.1"),
662     host = Some("127.0.0.1"),
663     path = "/",
664     query = None,
665     fragment = Some("foo/bar"),
666     port = None,
667 }
668 
669 test_parse! {
670     test_uri_parse_absolute_form_with_empty_path_and_fragment_with_questionmark,
671     "http://127.0.0.1#foo?bar",
672     scheme = Some("http"),
673     authority = Some("127.0.0.1"),
674     host = Some("127.0.0.1"),
675     path = "/",
676     query = None,
677     fragment = Some("foo?bar"),
678     port = None,
679 
680     to_string = "http://127.0.0.1/#foo?bar",
681 }
682 
683 #[test]
test_uri_parse_error()684 fn test_uri_parse_error() {
685     fn err(s: &str) {
686         Uri::from_str(s).unwrap_err();
687     }
688 
689     err("http://");
690     err("htt:p//host");
691     err("hyper.rs/");
692     err("hyper.rs?key=val");
693     err("?key=val");
694     err("localhost/");
695     err("localhost?key=val");
696     err("http://::1]");
697     err("http://[::1");
698 }
699 
700 #[test]
test_uri_to_origin_form()701 fn test_uri_to_origin_form() {
702     let cases = vec![
703         ("/", "/"),
704         ("/foo?bar", "/foo?bar"),
705         ("/foo?bar#nope", "/foo?bar"),
706         ("http://hyper.rs", "/"),
707         ("http://hyper.rs/", "/"),
708         ("http://hyper.rs/path", "/path"),
709         ("http://hyper.rs?query", "/?query"),
710         ("*", "*"),
711     ];
712 
713     for case in cases {
714         let uri = Uri::from_str(case.0).unwrap();
715         assert_eq!(origin_form(&uri), case.1); //, "{:?}", case);
716     }
717 }
718