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 
parse_scheme(s: &str) -> Option<usize>242 fn parse_scheme(s: &str) -> Option<usize> {
243     s.find(':')
244 }
245 
parse_authority(s: &str) -> usize246 fn parse_authority(s: &str) -> usize {
247     let i = s.find("://").map(|p| p + 3).unwrap_or(0);
248     s[i..]
249         .find(|ch| ch == '/' || ch == '?' || ch == '#')
250         .map(|end| end + i)
251         .unwrap_or(s.len())
252 }
253 
parse_query(s: &str) -> Option<usize>254 fn parse_query(s: &str) -> Option<usize> {
255     s.find('?').and_then(|i| {
256         if let Some(frag) = s.find('#') {
257             if frag < i {
258                 None
259             } else {
260                 Some(i)
261             }
262         } else {
263             Some(i)
264         }
265     })
266 }
267 
parse_fragment(s: &str) -> Option<usize>268 fn parse_fragment(s: &str) -> Option<usize> {
269     s.find('#')
270 }
271 
272 impl FromStr for Uri {
273     type Err = UriError;
274 
from_str(s: &str) -> Result<Uri, UriError>275     fn from_str(s: &str) -> Result<Uri, UriError> {
276         //TODO: refactor such that the to_owned() is only required at the end
277         //of successful parsing, so an Err doesn't needlessly clone the string.
278         Uri::new(ByteStr::from(s))
279     }
280 }
281 
282 impl PartialEq for Uri {
eq(&self, other: &Uri) -> bool283     fn eq(&self, other: &Uri) -> bool {
284         self.source.as_str() == other.source.as_str()
285     }
286 }
287 
288 impl PartialEq<str> for Uri {
eq(&self, other: &str) -> bool289     fn eq(&self, other: &str) -> bool {
290         self.source.as_str() == other
291     }
292 }
293 
294 // FIXME delete for 0.12
295 impl<'a> PartialEq<&'a str> for Uri {
eq(&self, other: & &'a str) -> bool296     fn eq(&self, other: & &'a str) -> bool {
297         self.source.as_str() == *other
298     }
299 }
300 
301 impl<'a> PartialEq<Uri> for &'a str{
eq(&self, other: &Uri) -> bool302     fn eq(&self, other: &Uri) -> bool {
303         *self == other.source.as_str()
304     }
305 }
306 
307 impl Eq for Uri {}
308 
309 impl AsRef<str> for Uri {
as_ref(&self) -> &str310     fn as_ref(&self) -> &str {
311         self.source.as_str()
312     }
313 }
314 
315 impl Default for Uri {
default() -> Uri316     fn default() -> Uri {
317         Uri {
318             source: ByteStr::from_static("/"),
319             scheme_end: None,
320             authority_end: None,
321             query_start: None,
322             fragment_start: None,
323         }
324     }
325 }
326 
327 impl fmt::Debug for Uri {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result328     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
329         fmt::Debug::fmt(self.as_ref(), f)
330     }
331 }
332 
333 impl Display for Uri {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result334     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
335         f.write_str(self.as_ref())
336     }
337 }
338 
339 #[cfg(feature = "compat")]
340 impl From<http::Uri> for Uri {
from(uri: http::Uri) -> Uri341     fn from(uri: http::Uri) -> Uri {
342         uri.to_string().parse()
343             .expect("attempted to convert invalid uri")
344     }
345 }
346 
347 #[cfg(feature = "compat")]
348 impl From<Uri> for http::Uri {
from(uri: Uri) -> http::Uri349     fn from(uri: Uri) -> http::Uri {
350         let bytes = uri.source.into_bytes();
351         http::Uri::from_shared(bytes)
352             .expect("attempted to convert invalid uri")
353     }
354 }
355 
from_utf8_unchecked(slice: Bytes) -> Result<Uri, UriError>356 pub unsafe fn from_utf8_unchecked(slice: Bytes) -> Result<Uri, UriError> {
357     Uri::new(ByteStr::from_utf8_unchecked(slice))
358 }
359 
scheme_and_authority(uri: &Uri) -> Option<Uri>360 pub fn scheme_and_authority(uri: &Uri) -> Option<Uri> {
361     if uri.scheme_end.is_some() {
362         Some(Uri {
363             source: uri.source.slice_to(uri.authority_end.expect("scheme without authority")),
364             scheme_end: uri.scheme_end,
365             authority_end: uri.authority_end,
366             query_start: None,
367             fragment_start: None,
368         })
369     } else {
370         None
371     }
372 }
373 
374 #[inline]
asterisk_form() -> Uri375 fn asterisk_form() -> Uri {
376     Uri {
377         source: ByteStr::from_static("*"),
378         scheme_end: None,
379         authority_end: None,
380         query_start: None,
381         fragment_start: None,
382     }
383 }
384 
origin_form(uri: &Uri) -> Uri385 pub fn origin_form(uri: &Uri) -> Uri {
386     let range = Range(uri.path_start(), uri.origin_form_end());
387 
388     let clone = if range.len() == 0 {
389         ByteStr::from_static("/")
390     } else if uri.source.as_bytes()[range.0] == b'*' {
391         return asterisk_form();
392     } else if uri.source.as_bytes()[range.0] != b'/' {
393         let mut new = BytesMut::with_capacity(range.1 - range.0 + 1);
394         new.put_u8(b'/');
395         new.put_slice(&uri.source.as_bytes()[range.0..range.1]);
396         // safety: the bytes are '/' + previous utf8 str
397         unsafe { ByteStr::from_utf8_unchecked(new.freeze()) }
398     } else if range.0 == 0 && range.1 == uri.source.len() {
399         uri.source.clone()
400     } else {
401         uri.source.slice(range.0, range.1)
402     };
403 
404     Uri {
405         source: clone,
406         scheme_end: None,
407         authority_end: None,
408         query_start: uri.query_start,
409         fragment_start: None,
410     }
411 }
412 
413 struct Range(usize, usize);
414 
415 impl Range {
len(&self) -> usize416     fn len(&self) -> usize {
417         self.1 - self.0
418     }
419 }
420 
421 /// An error parsing a `Uri`.
422 #[derive(Clone, Debug)]
423 pub struct UriError(ErrorKind);
424 
425 #[derive(Clone, Debug)]
426 enum ErrorKind {
427     Empty,
428     Malformed,
429     MissingAuthority,
430 }
431 
432 impl fmt::Display for UriError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result433     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
434         f.pad(self.description())
435     }
436 }
437 
438 impl StdError for UriError {
description(&self) -> &str439     fn description(&self) -> &str {
440         match self.0 {
441             ErrorKind::Empty => "empty Uri string",
442             ErrorKind::Malformed => "invalid character in Uri authority",
443             ErrorKind::MissingAuthority => "absolute Uri missing authority segment",
444         }
445     }
446 }
447 
448 macro_rules! test_parse {
449     (
450         $test_name:ident,
451         $str:expr,
452         $($method:ident = $value:expr,)*
453     ) => (
454         #[test]
455         fn $test_name() {
456             let uri = Uri::from_str($str).unwrap();
457             $(
458             assert_eq!(uri.$method(), $value, stringify!($method));
459             )+
460         }
461     );
462 }
463 
464 test_parse! {
465     test_uri_parse_origin_form,
466     "/some/path/here?and=then&hello#and-bye",
467 
468     scheme = None,
469     authority = None,
470     path = "/some/path/here",
471     query = Some("and=then&hello"),
472     fragment = Some("and-bye"),
473 }
474 
475 test_parse! {
476     test_uri_parse_absolute_form,
477     "http://127.0.0.1:61761/chunks",
478 
479     scheme = Some("http"),
480     authority = Some("127.0.0.1:61761"),
481     host = Some("127.0.0.1"),
482     path = "/chunks",
483     query = None,
484     fragment = None,
485     port = Some(61761),
486 }
487 
488 test_parse! {
489     test_uri_parse_absolute_form_without_path,
490     "https://127.0.0.1:61761",
491 
492     scheme = Some("https"),
493     authority = Some("127.0.0.1:61761"),
494     host = Some("127.0.0.1"),
495     path = "/",
496     query = None,
497     fragment = None,
498     port = Some(61761),
499 
500     to_string = "https://127.0.0.1:61761/",
501 }
502 
503 test_parse! {
504     test_uri_parse_asterisk_form,
505     "*",
506 
507     scheme = None,
508     authority = None,
509     path = "*",
510     query = None,
511     fragment = None,
512 
513     to_string = "*",
514 }
515 
516 test_parse! {
517     test_uri_parse_authority_no_port,
518     "localhost",
519 
520     scheme = None,
521     authority = Some("localhost"),
522     host = Some("localhost"),
523     path = "",
524     query = None,
525     fragment = None,
526     port = None,
527 
528     to_string = "localhost",
529 }
530 
531 test_parse! {
532     test_uri_parse_authority_form,
533     "localhost:3000",
534 
535     scheme = None,
536     authority = Some("localhost:3000"),
537     host = Some("localhost"),
538     path = "",
539     query = None,
540     fragment = None,
541     port = Some(3000),
542 }
543 
544 test_parse! {
545     test_uri_parse_absolute_with_default_port_http,
546     "http://127.0.0.1:80/foo",
547 
548     scheme = Some("http"),
549     authority = Some("127.0.0.1:80"),
550     host = Some("127.0.0.1"),
551     path = "/foo",
552     query = None,
553     fragment = None,
554     port = Some(80),
555 }
556 
557 test_parse! {
558     test_uri_parse_absolute_with_default_port_https,
559     "https://127.0.0.1:443",
560 
561     scheme = Some("https"),
562     authority = Some("127.0.0.1:443"),
563     host = Some("127.0.0.1"),
564     path = "/",
565     query = None,
566     fragment = None,
567     port = Some(443),
568 }
569 
570 test_parse! {
571     test_uri_parse_absolute_with_ipv6,
572     "https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8008",
573 
574     scheme = Some("https"),
575     authority = Some("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8008"),
576     host = Some("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
577     path = "/",
578     query = None,
579     fragment = None,
580     port = Some(8008),
581 }
582 
583 test_parse! {
584     test_uri_parse_absolute_with_ipv6_and_no_port,
585     "https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]",
586 
587     scheme = Some("https"),
588     authority = Some("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"),
589     host = Some("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
590     path = "/",
591     query = None,
592     fragment = None,
593     port = None,
594 }
595 
596 test_parse! {
597     test_uri_parse_absolute_with_userinfo,
598     "https://seanmonstar:password@hyper.rs",
599 
600     scheme = Some("https"),
601     authority = Some("seanmonstar:password@hyper.rs"),
602     host = Some("hyper.rs"),
603     path = "/",
604     query = None,
605     fragment = None,
606     port = None,
607 }
608 
609 test_parse! {
610     test_uri_parse_fragment_questionmark,
611     "http://127.0.0.1/#?",
612 
613     scheme = Some("http"),
614     authority = Some("127.0.0.1"),
615     host = Some("127.0.0.1"),
616     path = "/",
617     query = None,
618     fragment = Some("?"),
619     port = None,
620 }
621 
622 test_parse! {
623     test_uri_parse_path_with_terminating_questionmark,
624     "http://127.0.0.1/path?",
625 
626     scheme = Some("http"),
627     authority = Some("127.0.0.1"),
628     host = Some("127.0.0.1"),
629     path = "/path",
630     query = Some(""),
631     fragment = None,
632     port = None,
633 }
634 
635 test_parse! {
636     test_uri_parse_absolute_form_with_empty_path_and_nonempty_query,
637     "http://127.0.0.1?foo=bar",
638 
639     scheme = Some("http"),
640     authority = Some("127.0.0.1"),
641     host = Some("127.0.0.1"),
642     path = "/",
643     query = Some("foo=bar"),
644     fragment = None,
645     port = None,
646 
647     to_string = "http://127.0.0.1/?foo=bar",
648 }
649 
650 test_parse! {
651     test_uri_parse_absolute_form_with_empty_path_and_fragment_with_slash,
652     "http://127.0.0.1#foo/bar",
653     scheme = Some("http"),
654     authority = Some("127.0.0.1"),
655     host = Some("127.0.0.1"),
656     path = "/",
657     query = None,
658     fragment = Some("foo/bar"),
659     port = None,
660 }
661 
662 test_parse! {
663     test_uri_parse_absolute_form_with_empty_path_and_fragment_with_questionmark,
664     "http://127.0.0.1#foo?bar",
665     scheme = Some("http"),
666     authority = Some("127.0.0.1"),
667     host = Some("127.0.0.1"),
668     path = "/",
669     query = None,
670     fragment = Some("foo?bar"),
671     port = None,
672 
673     to_string = "http://127.0.0.1/#foo?bar",
674 }
675 
676 #[test]
test_uri_parse_error()677 fn test_uri_parse_error() {
678     fn err(s: &str) {
679         Uri::from_str(s).unwrap_err();
680     }
681 
682     err("http://");
683     err("htt:p//host");
684     err("hyper.rs/");
685     err("hyper.rs?key=val");
686     err("?key=val");
687     err("localhost/");
688     err("localhost?key=val");
689     err("http://::1]");
690     err("http://[::1");
691 }
692 
693 #[test]
test_uri_to_origin_form()694 fn test_uri_to_origin_form() {
695     let cases = vec![
696         ("/", "/"),
697         ("/foo?bar", "/foo?bar"),
698         ("/foo?bar#nope", "/foo?bar"),
699         ("http://hyper.rs", "/"),
700         ("http://hyper.rs/", "/"),
701         ("http://hyper.rs/path", "/path"),
702         ("http://hyper.rs?query", "/?query"),
703         ("*", "*"),
704     ];
705 
706     for case in cases {
707         let uri = Uri::from_str(case.0).unwrap();
708         assert_eq!(origin_form(&uri), case.1); //, "{:?}", case);
709     }
710 }
711