From 8fa7a9896809ef2a24994993b91981105a520f26 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 22 Apr 2016 01:14:08 +0200 Subject: [PATCH] refactor(hyper): Update to rust-url 1.0 BREAKING CHANGE: The re-exported Url type has breaking changes. --- Cargo.toml | 2 +- src/client/mod.rs | 15 +++++------ src/client/request.rs | 21 +++++++++------ src/header/common/content_disposition.rs | 5 ++-- src/header/parsing.rs | 14 +++++++--- src/http/h1.rs | 33 ++++++++++++------------ src/http/h2.rs | 14 ++-------- src/lib.rs | 2 +- src/uri.rs | 2 +- 9 files changed, 54 insertions(+), 54 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8364187334..0ced4e0e2e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ time = "0.1" traitobject = "0.0.1" typeable = "0.1" unicase = "1.0" -url = "0.5" +url = "1.0" [dependencies.cookie] version = "0.2" diff --git a/src/client/mod.rs b/src/client/mod.rs index 37969092d7..171da0a71a 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -62,14 +62,13 @@ use std::fmt; use std::time::Duration; -use url::UrlParser; +use url::Url; use url::ParseError as UrlError; use header::{Headers, Header, HeaderFormat}; use header::{ContentLength, Location}; use method::Method; use net::{NetworkConnector, NetworkStream}; -use {Url}; use Error; pub use self::pool::Pool; @@ -264,7 +263,7 @@ impl<'a> RequestBuilder<'a> { loop { let message = { let (host, port) = try!(get_host_and_port(&url)); - try!(client.protocol.new_message(&host, port, &*url.scheme)) + try!(client.protocol.new_message(&host, port, url.scheme())) }; let mut req = try!(Request::with_message(method.clone(), url.clone(), message)); headers.as_ref().map(|headers| req.headers_mut().extend(headers.iter())); @@ -292,7 +291,7 @@ impl<'a> RequestBuilder<'a> { // punching borrowck here let loc = match res.headers.get::() { Some(&Location(ref loc)) => { - Some(UrlParser::new().base_url(&url).parse(&loc[..])) + Some(url.join(loc)) } None => { debug!("no Location header"); @@ -439,13 +438,13 @@ impl Default for RedirectPolicy { } } -fn get_host_and_port(url: &Url) -> ::Result<(String, u16)> { - let host = match url.serialize_host() { +fn get_host_and_port(url: &Url) -> ::Result<(&str, u16)> { + let host = match url.host_str() { Some(host) => host, None => return Err(Error::Uri(UrlError::EmptyHost)) }; trace!("host={:?}", host); - let port = match url.port_or_default() { + let port = match url.port_or_known_default() { Some(port) => port, None => return Err(Error::Uri(UrlError::InvalidPort)) }; @@ -498,7 +497,7 @@ mod tests { #[test] fn test_redirect_followif() { fn follow_if(url: &Url) -> bool { - !url.serialize().contains("127.0.0.3") + !url.as_str().contains("127.0.0.3") } let mut client = Client::with_connector(MockRedirectPolicy); client.set_redirect_policy(RedirectPolicy::FollowIf(follow_if)); diff --git a/src/client/request.rs b/src/client/request.rs index 7c3060c338..612f944d65 100644 --- a/src/client/request.rs +++ b/src/client/request.rs @@ -61,12 +61,14 @@ impl Request { /// properly initialized by the caller (e.g. a TCP connection's already established). pub fn with_message(method: Method, url: Url, message: Box) -> ::Result> { - let (host, port) = try!(get_host_and_port(&url)); let mut headers = Headers::new(); - headers.set(Host { - hostname: host, - port: Some(port), - }); + { + let (host, port) = try!(get_host_and_port(&url)); + headers.set(Host { + hostname: host.to_owned(), + port: Some(port), + }); + } Ok(Request { method: method, @@ -89,8 +91,10 @@ impl Request { -> ::Result> where C: NetworkConnector, S: Into> { - let (host, port) = try!(get_host_and_port(&url)); - let stream = try!(connector.connect(&*host, port, &*url.scheme)).into(); + let stream = { + let (host, port) = try!(get_host_and_port(&url)); + try!(connector.connect(host, port, url.scheme())).into() + }; Request::with_message(method, url, Box::new(Http11Message::with_stream(stream))) } @@ -223,7 +227,8 @@ mod tests { let mut req = Request::with_connector( Post, url, &mut MockConnector ).unwrap(); - let body = form_urlencoded::serialize(vec!(("q","value")).into_iter()); + let mut body = String::new(); + form_urlencoded::Serializer::new(&mut body).append_pair("q", "value"); req.headers_mut().set(ContentLength(body.len() as u64)); let bytes = run_request(req); let s = from_utf8(&bytes[..]).unwrap(); diff --git a/src/header/common/content_disposition.rs b/src/header/common/content_disposition.rs index 7816479f51..e6d38743d2 100644 --- a/src/header/common/content_disposition.rs +++ b/src/header/common/content_disposition.rs @@ -12,7 +12,7 @@ use unicase::UniCase; use url::percent_encoding; use header::{Header, HeaderFormat, parsing}; -use header::parsing::parse_extended_value; +use header::parsing::{parse_extended_value, HTTP_VALUE}; use header::shared::Charset; /// The implied disposition of the content of the HTTP body @@ -184,8 +184,7 @@ impl fmt::Display for ContentDisposition { }; try!(write!(f, "'")); try!(f.write_str( - &*percent_encoding::percent_encode( - bytes, percent_encoding::HTTP_VALUE_ENCODE_SET))) + &percent_encoding::percent_encode(bytes, HTTP_VALUE).to_string())) } }, DispositionParam::Ext(ref k, ref v) => try!(write!(f, "; {}=\"{}\"", k, v)), diff --git a/src/header/parsing.rs b/src/header/parsing.rs index bbb158b0eb..38c09db5e7 100644 --- a/src/header/parsing.rs +++ b/src/header/parsing.rs @@ -118,7 +118,7 @@ pub fn parse_extended_value(val: &str) -> ::Result { // Interpret the third piece as a sequence of value characters let value: Vec = match parts.next() { None => return Err(::Error::Header), - Some(v) => percent_encoding::percent_decode(v.as_bytes()), + Some(v) => percent_encoding::percent_decode(v.as_bytes()).collect(), }; Ok(ExtendedValue { @@ -128,11 +128,19 @@ pub fn parse_extended_value(val: &str) -> ::Result { }) } +define_encode_set! { + /// This encode set is used for HTTP header values and is defined at + /// https://tools.ietf.org/html/rfc5987#section-3.2 + pub HTTP_VALUE = [percent_encoding::SIMPLE_ENCODE_SET] | { + ' ', '"', '%', '\'', '(', ')', '*', ',', '/', ':', ';', '<', '-', '>', '?', + '[', '\\', ']', '{', '}' + } +} + impl Display for ExtendedValue { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let encoded_value = - percent_encoding::percent_encode(&self.value[..], - percent_encoding::HTTP_VALUE_ENCODE_SET); + percent_encoding::percent_encode(&self.value[..], HTTP_VALUE); if let Some(ref lang) = self.language_tag { write!(f, "{}'{}'{}", self.charset, lang, encoded_value) } else { diff --git a/src/http/h1.rs b/src/http/h1.rs index 669a753e58..63246e2819 100644 --- a/src/http/h1.rs +++ b/src/http/h1.rs @@ -7,6 +7,7 @@ use std::net::Shutdown; use std::time::Duration; use httparse; +use url::Position as UrlPosition; use buffer::BufReader; use Error; @@ -142,25 +143,23 @@ impl HttpMessage for Http11Message { }; let mut stream = BufWriter::new(stream); - let mut uri = head.url.serialize_path().unwrap(); - if let Some(ref q) = head.url.query { - uri.push('?'); - uri.push_str(&q[..]); + { + let uri = &head.url[UrlPosition::BeforePath..UrlPosition::AfterQuery]; + + let version = version::HttpVersion::Http11; + debug!("request line: {:?} {:?} {:?}", head.method, uri, version); + match write!(&mut stream, "{} {} {}{}", + head.method, uri, version, LINE_ENDING) { + Err(e) => { + res = Err(From::from(e)); + // TODO What should we do if the BufWriter doesn't wanna + // relinquish the stream? + return Stream::Idle(stream.into_inner().ok().unwrap()); + }, + Ok(_) => {}, + }; } - let version = version::HttpVersion::Http11; - debug!("request line: {:?} {:?} {:?}", head.method, uri, version); - match write!(&mut stream, "{} {} {}{}", - head.method, uri, version, LINE_ENDING) { - Err(e) => { - res = Err(From::from(e)); - // TODO What should we do if the BufWriter doesn't wanna - // relinquish the stream? - return Stream::Idle(stream.into_inner().ok().unwrap()); - }, - Ok(_) => {}, - }; - let stream = { let write_headers = |mut stream: BufWriter>, head: &RequestHead| { debug!("headers={:?}", head.headers); diff --git a/src/http/h2.rs b/src/http/h2.rs index cda4f0ca94..95ac5e5242 100644 --- a/src/http/h2.rs +++ b/src/http/h2.rs @@ -15,7 +15,7 @@ use http::{ }; use net::{NetworkStream, NetworkConnector}; use net::{HttpConnector, HttpStream}; -use url::Url; +use url::Position as UrlPosition; use header::Headers; use header; @@ -262,16 +262,6 @@ impl Read for Http2Message where S: CloneableStream { } } -/// A helper function that prepares the path of a request by extracting it from the given `Url`. -fn prepare_path(url: Url) -> Vec { - let mut uri = url.serialize_path().unwrap(); - if let Some(ref q) = url.query { - uri.push('?'); - uri.push_str(&q[..]); - } - uri.into_bytes() -} - /// A helper function that prepares the headers that should be sent in an HTTP/2 message. /// /// Adapts the `Headers` into a list of octet string pairs. @@ -374,7 +364,7 @@ impl HttpMessage for Http2Message where S: CloneableStream { let (RequestHead { headers, method, url }, body) = (request.head, request.body); let method = method.as_ref().as_bytes(); - let path = prepare_path(url); + let path = url[UrlPosition::BeforePath..UrlPosition::AfterQuery].as_bytes(); let extra_headers = prepare_headers(headers); let body = prepare_body(body); diff --git a/src/lib.rs b/src/lib.rs index 7f8704c697..8343caff8c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -130,7 +130,7 @@ extern crate rustc_serialize as serialize; extern crate time; -extern crate url; +#[macro_use] extern crate url; #[cfg(feature = "openssl")] extern crate openssl; #[cfg(feature = "security-framework")] diff --git a/src/uri.rs b/src/uri.rs index 2a746f4888..a5a9860fed 100644 --- a/src/uri.rs +++ b/src/uri.rs @@ -56,7 +56,7 @@ impl FromStr for RequestUri { fn from_str(s: &str) -> Result { let bytes = s.as_bytes(); if bytes == [] { - Err(Error::Uri(UrlError::InvalidCharacter)) + Err(Error::Uri(UrlError::RelativeUrlWithoutBase)) } else if bytes == b"*" { Ok(RequestUri::Star) } else if bytes.starts_with(b"/") {