| @@ -344,7 +344,7 @@ mod tests { | |||||||
|         let (req, len) = parse::<http::ServerTransaction, _>(&mut raw).unwrap().unwrap(); |         let (req, len) = parse::<http::ServerTransaction, _>(&mut raw).unwrap().unwrap(); | ||||||
|         assert_eq!(len, expected_len); |         assert_eq!(len, expected_len); | ||||||
|         assert_eq!(req.subject.0, ::Method::Get); |         assert_eq!(req.subject.0, ::Method::Get); | ||||||
|         assert_eq!(req.subject.1, "/echo".parse().unwrap()); |         assert_eq!(req.subject.1, "/echo"); | ||||||
|         assert_eq!(req.version, ::HttpVersion::Http11); |         assert_eq!(req.version, ::HttpVersion::Http11); | ||||||
|         assert_eq!(req.headers.len(), 1); |         assert_eq!(req.headers.len(), 1); | ||||||
|         assert_eq!(req.headers.get_raw("Host").map(|raw| &raw[0]), Some(b"hyper.rs".as_ref())); |         assert_eq!(req.headers.get_raw("Host").map(|raw| &raw[0]), Some(b"hyper.rs".as_ref())); | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| use std::ops::Deref; | use std::ops::Deref; | ||||||
| use std::str; | use std::str; | ||||||
|  |  | ||||||
| use bytes::Bytes; | use bytes::{Bytes, BytesMut}; | ||||||
|  |  | ||||||
| #[derive(Debug, Clone, PartialEq, Eq, Hash)] | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||||||
| pub struct ByteStr(Bytes); | pub struct ByteStr(Bytes); | ||||||
| @@ -38,6 +38,19 @@ impl Deref for ByteStr { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | impl From<ByteStr> for Bytes { | ||||||
|  |     fn from(s: ByteStr) -> Bytes { | ||||||
|  |         s.0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl From<ByteStr> for BytesMut { | ||||||
|  |     fn from(s: ByteStr) -> BytesMut { | ||||||
|  |         s.0.into() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| impl<'a> From<&'a str> for ByteStr { | impl<'a> From<&'a str> for ByteStr { | ||||||
|     fn from(s: &'a str) -> ByteStr { |     fn from(s: &'a str) -> ByteStr { | ||||||
|         ByteStr(Bytes::from(s)) |         ByteStr(Bytes::from(s)) | ||||||
|   | |||||||
							
								
								
									
										94
									
								
								src/uri.rs
									
									
									
									
									
								
							
							
						
						
									
										94
									
								
								src/uri.rs
									
									
									
									
									
								
							| @@ -3,6 +3,7 @@ use std::fmt::{Display, self}; | |||||||
| use std::str::{self, FromStr}; | use std::str::{self, FromStr}; | ||||||
|  |  | ||||||
| use http::ByteStr; | use http::ByteStr; | ||||||
|  | use bytes::{BufMut, BytesMut}; | ||||||
|  |  | ||||||
| /// The Request-URI of a Request's StartLine. | /// The Request-URI of a Request's StartLine. | ||||||
| /// | /// | ||||||
| @@ -101,14 +102,8 @@ impl Uri { | |||||||
|  |  | ||||||
|     /// Get the path of this `Uri`. |     /// Get the path of this `Uri`. | ||||||
|     pub fn path(&self) -> &str { |     pub fn path(&self) -> &str { | ||||||
|         let index = self.authority_end.unwrap_or(self.scheme_end.unwrap_or(0)); |         let index = self.path_start(); | ||||||
|         let end = if let Some(query) = self.query_start { |         let end = self.path_end(); | ||||||
|             query |  | ||||||
|         } else if let Some(fragment) = self.fragment_start { |  | ||||||
|             fragment |  | ||||||
|         } else { |  | ||||||
|             self.source.len() |  | ||||||
|         }; |  | ||||||
|         if index >= end { |         if index >= end { | ||||||
|             if self.scheme().is_some() { |             if self.scheme().is_some() { | ||||||
|                 "/" // absolute-form MUST have path |                 "/" // absolute-form MUST have path | ||||||
| @@ -120,6 +115,31 @@ impl Uri { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     #[inline] | ||||||
|  |     fn path_start(&self) -> usize { | ||||||
|  |         self.authority_end.unwrap_or(self.scheme_end.unwrap_or(0)) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[inline] | ||||||
|  |     fn path_end(&self) -> usize { | ||||||
|  |         if let Some(query) = self.query_start { | ||||||
|  |             query | ||||||
|  |         } else if let Some(fragment) = self.fragment_start { | ||||||
|  |             fragment | ||||||
|  |         } else { | ||||||
|  |             self.source.len() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[inline] | ||||||
|  |     fn origin_form_end(&self) -> usize { | ||||||
|  |         if let Some(fragment) = self.fragment_start { | ||||||
|  |             fragment | ||||||
|  |         } else { | ||||||
|  |             self.source.len() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// Get the scheme of this `Uri`. |     /// Get the scheme of this `Uri`. | ||||||
|     pub fn scheme(&self) -> Option<&str> { |     pub fn scheme(&self) -> Option<&str> { | ||||||
|         if let Some(end) = self.scheme_end { |         if let Some(end) = self.scheme_end { | ||||||
| @@ -226,6 +246,18 @@ impl PartialEq for Uri { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl<'a> PartialEq<&'a str> for Uri { | ||||||
|  |     fn eq(&self, other: & &'a str) -> bool { | ||||||
|  |         self.source.as_str() == *other | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<'a> PartialEq<Uri> for &'a str{ | ||||||
|  |     fn eq(&self, other: &Uri) -> bool { | ||||||
|  |         *self == other.source.as_str() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| impl Eq for Uri {} | impl Eq for Uri {} | ||||||
|  |  | ||||||
| impl AsRef<str> for Uri { | impl AsRef<str> for Uri { | ||||||
| @@ -277,14 +309,24 @@ pub fn scheme_and_authority(uri: &Uri) -> Option<Uri> { | |||||||
| } | } | ||||||
|  |  | ||||||
| pub fn origin_form(uri: &Uri) -> Uri { | pub fn origin_form(uri: &Uri) -> Uri { | ||||||
|     let start = uri.authority_end.unwrap_or(uri.scheme_end.unwrap_or(0)); |     let range = Range(uri.path_start(), uri.origin_form_end()); | ||||||
|     let end = if let Some(f) = uri.fragment_start { |  | ||||||
|         f |     let clone = if range.len() == 0 { | ||||||
|  |         ByteStr::from_static("/") | ||||||
|  |     } else if uri.source.as_bytes()[range.0] != b'/' { | ||||||
|  |         let mut new = BytesMut::with_capacity(range.1 - range.0 + 1); | ||||||
|  |         new.put_u8(b'/'); | ||||||
|  |         new.put_slice(&uri.source.as_bytes()[range.0..range.1]); | ||||||
|  |         // safety: the bytes are '/' + previous utf8 str | ||||||
|  |         unsafe { ByteStr::from_utf8_unchecked(new.freeze()) } | ||||||
|  |     } else if range.0 == 0 && range.1 == uri.source.len() { | ||||||
|  |         uri.source.clone() | ||||||
|     } else { |     } else { | ||||||
|         uri.source.len() |         uri.source.slice(range.0, range.1) | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     Uri { |     Uri { | ||||||
|         source: uri.source.slice(start, end), |         source: clone, | ||||||
|         scheme_end: None, |         scheme_end: None, | ||||||
|         authority_end: None, |         authority_end: None, | ||||||
|         query_start: uri.query_start, |         query_start: uri.query_start, | ||||||
| @@ -292,6 +334,14 @@ pub fn origin_form(uri: &Uri) -> Uri { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | struct Range(usize, usize); | ||||||
|  |  | ||||||
|  | impl Range { | ||||||
|  |     fn len(&self) -> usize { | ||||||
|  |         self.1 - self.0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| /// An error parsing a `Uri`. | /// An error parsing a `Uri`. | ||||||
| #[derive(Clone, Debug)] | #[derive(Clone, Debug)] | ||||||
| pub struct UriError(ErrorKind); | pub struct UriError(ErrorKind); | ||||||
| @@ -480,3 +530,21 @@ fn test_uri_parse_error() { | |||||||
|     err("localhost/"); |     err("localhost/"); | ||||||
|     err("localhost?key=val"); |     err("localhost?key=val"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[test] | ||||||
|  | fn test_uri_to_origin_form() { | ||||||
|  |     let cases = vec![ | ||||||
|  |         ("/", "/"), | ||||||
|  |         ("/foo?bar", "/foo?bar"), | ||||||
|  |         ("/foo?bar#nope", "/foo?bar"), | ||||||
|  |         ("http://hyper.rs", "/"), | ||||||
|  |         ("http://hyper.rs/", "/"), | ||||||
|  |         ("http://hyper.rs/path", "/path"), | ||||||
|  |         ("http://hyper.rs?query", "/?query"), | ||||||
|  |     ]; | ||||||
|  |  | ||||||
|  |     for case in cases { | ||||||
|  |         let uri = Uri::from_str(case.0).unwrap(); | ||||||
|  |         assert_eq!(origin_form(&uri), case.1); | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user