diff --git a/Cargo.toml b/Cargo.toml index e7774db..9303979 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "reqwest" -version = "0.8.6" # remember to update html_root_url +version = "0.9.0-pre" # remember to update html_root_url description = "higher level HTTP client library" keywords = ["http", "request", "client"] repository = "https://github.com/seanmonstar/reqwest" @@ -9,20 +9,26 @@ authors = ["Sean McArthur "] license = "MIT/Apache-2.0" categories = ["web-programming::http-client"] +publish = false # pre + [dependencies] +base64 = "~0.6.0" bytes = "0.4" encoding_rs = "0.7" -futures = "0.1.15" -hyper = "0.11.22" -hyper-tls = "0.1.2" +futures = "0.1.21" +http = "0.1.5" +hyper = "0.12.2" +hyper-tls = "0.2.1" libflate = "0.1.11" log = "0.4" -mime_guess = "2.0.0-alpha.2" +mime = "0.3.7" +mime_guess = "2.0.0-alpha.4" native-tls = "0.1.5" serde = "1.0" serde_json = "1.0" serde_urlencoded = "0.5" -tokio-core = "0.1.6" +tokio-core = "0.1.17" +tokio = "0.1.7" tokio-io = "0.1" tokio-tls = "0.1" url = "1.2" diff --git a/examples/async.rs b/examples/async.rs index 222acde..8de7f88 100644 --- a/examples/async.rs +++ b/examples/async.rs @@ -20,7 +20,7 @@ error_chain! { fn run() -> Result<()> { let mut core = tokio_core::reactor::Core::new()?; - let client = Client::new(&core.handle()); + let client = Client::new(); let work = client.get("https://hyper.rs") .send() diff --git a/examples/simple.rs b/examples/simple.rs index 16384f7..d23f702 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -22,7 +22,7 @@ fn run() -> Result<()> { let mut res = reqwest::get("https://www.rust-lang.org/en-US/")?; println!("Status: {}", res.status()); - println!("Headers:\n{}", res.headers()); + println!("Headers:\n{:?}", res.headers()); // copy the response body directly to stdout let _ = std::io::copy(&mut res, &mut std::io::stdout())?; diff --git a/src/async_impl/body.rs b/src/async_impl/body.rs index 2ef365a..a16426f 100644 --- a/src/async_impl/body.rs +++ b/src/async_impl/body.rs @@ -2,6 +2,7 @@ use std::fmt; use futures::{Stream, Poll, Async}; use bytes::Bytes; +use hyper::body::Payload; /// An asynchronous `Stream`. pub struct Body { @@ -20,6 +21,13 @@ impl Body { Inner::Reusable(_) => unreachable!(), } } + + pub(crate) fn content_length(&self) -> Option { + match self.inner { + Inner::Reusable(ref bytes) => Some(bytes.len() as u64), + Inner::Hyper(ref body) => body.content_length(), + } + } } impl Stream for Body { diff --git a/src/async_impl/client.rs b/src/async_impl/client.rs index 8fff979..1546524 100644 --- a/src/async_impl/client.rs +++ b/src/async_impl/client.rs @@ -4,11 +4,11 @@ use std::time::Duration; use bytes::Bytes; use futures::{Async, Future, Poll}; -use hyper::client::FutureResponse; -use hyper::header::{Headers, Location, Referer, UserAgent, Accept, Encoding, - AcceptEncoding, Range, qitem}; +use hyper::client::ResponseFuture; +use header::{HeaderMap, HeaderValue, LOCATION, USER_AGENT, REFERER, ACCEPT, + ACCEPT_ENCODING, RANGE}; +use mime::{self}; use native_tls::{TlsConnector, TlsConnectorBuilder}; -use tokio_core::reactor::Handle; use super::body; @@ -63,7 +63,7 @@ pub struct ClientBuilder { struct Config { gzip: bool, - headers: Headers, + headers: HeaderMap, hostname_verification: bool, proxies: Vec, redirect_policy: RedirectPolicy, @@ -78,9 +78,9 @@ impl ClientBuilder { pub fn new() -> ClientBuilder { match TlsConnector::builder() { Ok(tls_connector_builder) => { - let mut headers = Headers::with_capacity(2); - headers.set(UserAgent::new(DEFAULT_USER_AGENT)); - headers.set(Accept::star()); + let mut headers: HeaderMap = HeaderMap::with_capacity(2); + headers.insert(USER_AGENT, HeaderValue::from_static(DEFAULT_USER_AGENT)); + headers.insert(ACCEPT, HeaderValue::from_str(mime::STAR_STAR.as_ref()).expect("unable to parse mime")); ClientBuilder { config: Some(Config { @@ -114,7 +114,7 @@ impl ClientBuilder { /// /// This method consumes the internal state of the builder. /// Trying to use this builder again after calling `build` will panic. - pub fn build(&mut self, handle: &Handle) -> ::Result { + pub fn build(&mut self) -> ::Result { if let Some(err) = self.err.take() { return Err(err); } @@ -126,14 +126,13 @@ impl ClientBuilder { let proxies = Arc::new(config.proxies); - let mut connector = Connector::new(config.dns_threads, tls, proxies.clone(), handle); + let mut connector = Connector::new(config.dns_threads, tls, proxies.clone()); if !config.hostname_verification { connector.danger_disable_hostname_verification(); } - let hyper_client = ::hyper::Client::configure() - .connector(connector) - .build(handle); + let hyper_client = ::hyper::Client::builder() + .build(connector); Ok(Client { inner: Arc::new(ClientRef { @@ -200,9 +199,11 @@ impl ClientBuilder { /// Sets the default headers for every request. #[inline] - pub fn default_headers(&mut self, headers: Headers) -> &mut ClientBuilder { + pub fn default_headers(&mut self, headers: HeaderMap) -> &mut ClientBuilder { if let Some(config) = config_mut(&mut self.config, &self.err) { - config.headers.extend(headers.iter()); + for (key, value) in headers.iter() { + config.headers.insert(key, value.clone()); + } } self } @@ -287,9 +288,9 @@ impl Client { /// initialized. Use `Client::builder()` if you wish to handle the failure /// as an `Error` instead of panicking. #[inline] - pub fn new(handle: &Handle) -> Client { + pub fn new() -> Client { ClientBuilder::new() - .build(handle) + .build() .expect("TLS failed to initialize") } @@ -305,7 +306,7 @@ impl Client { /// /// This method fails whenever supplied `Url` cannot be parsed. pub fn get(&self, url: U) -> RequestBuilder { - self.request(Method::Get, url) + self.request(Method::GET, url) } /// Convenience method to make a `POST` request to a URL. @@ -314,7 +315,7 @@ impl Client { /// /// This method fails whenever supplied `Url` cannot be parsed. pub fn post(&self, url: U) -> RequestBuilder { - self.request(Method::Post, url) + self.request(Method::POST, url) } /// Convenience method to make a `PUT` request to a URL. @@ -323,7 +324,7 @@ impl Client { /// /// This method fails whenever supplied `Url` cannot be parsed. pub fn put(&self, url: U) -> RequestBuilder { - self.request(Method::Put, url) + self.request(Method::PUT, url) } /// Convenience method to make a `PATCH` request to a URL. @@ -332,7 +333,7 @@ impl Client { /// /// This method fails whenever supplied `Url` cannot be parsed. pub fn patch(&self, url: U) -> RequestBuilder { - self.request(Method::Patch, url) + self.request(Method::PATCH, url) } /// Convenience method to make a `DELETE` request to a URL. @@ -341,7 +342,7 @@ impl Client { /// /// This method fails whenever supplied `Url` cannot be parsed. pub fn delete(&self, url: U) -> RequestBuilder { - self.request(Method::Delete, url) + self.request(Method::DELETE, url) } /// Convenience method to make a `HEAD` request to a URL. @@ -350,7 +351,7 @@ impl Client { /// /// This method fails whenever supplied `Url` cannot be parsed. pub fn head(&self, url: U) -> RequestBuilder { - self.request(Method::Head, url) + self.request(Method::HEAD, url) } /// Start building a `Request` with the `Method` and `Url`. @@ -395,28 +396,35 @@ impl Client { ) = request::pieces(req); let mut headers = self.inner.headers.clone(); // default headers - headers.extend(user_headers.iter()); + for (key, value) in user_headers.iter() { + headers.insert(key, value.clone()); + } if self.inner.gzip && - !headers.has::() && - !headers.has::() { - headers.set(AcceptEncoding(vec![qitem(Encoding::Gzip)])); + !headers.contains_key(ACCEPT_ENCODING) && + !headers.contains_key(RANGE) { + headers.insert(ACCEPT_ENCODING, HeaderValue::from_static("gzip")); } let uri = to_uri(&url); - let mut req = ::hyper::Request::new(method.clone(), uri.clone()); - *req.headers_mut() = headers.clone(); - let body = body.map(|body| { - let (reusable, body) = body::into_hyper(body); - req.set_body(body); - reusable - }); - if proxy::is_proxied(&self.inner.proxies, &url) { - if uri.scheme() == Some("http") { - req.set_proxy(true); + let (reusable, body) = match body { + Some(body) => { + let (reusable, body) = body::into_hyper(body); + (Some(reusable), body) + }, + None => { + (None, ::hyper::Body::empty()) } - } + }; + + let mut req = ::hyper::Request::builder() + .method(method.clone()) + .uri(uri.clone()) + .body(body) + .expect("valid request parts"); + + *req.headers_mut() = headers.clone(); let in_flight = self.inner.hyper.request(req); @@ -425,7 +433,7 @@ impl Client { method: method, url: url, headers: headers, - body: body, + body: reusable, urls: Vec::new(), @@ -456,7 +464,7 @@ impl fmt::Debug for ClientBuilder { struct ClientRef { gzip: bool, - headers: Headers, + headers: HeaderMap, hyper: HyperClient, proxies: Arc>, redirect_policy: RedirectPolicy, @@ -475,14 +483,14 @@ enum PendingInner { pub struct PendingRequest { method: Method, url: Url, - headers: Headers, + headers: HeaderMap, body: Option>, urls: Vec, client: Arc, - in_flight: FutureResponse, + in_flight: ResponseFuture, } @@ -509,20 +517,20 @@ impl Future for PendingRequest { Async::NotReady => return Ok(Async::NotReady), }; let should_redirect = match res.status() { - StatusCode::MovedPermanently | - StatusCode::Found | - StatusCode::SeeOther => { + StatusCode::MOVED_PERMANENTLY | + StatusCode::FOUND | + StatusCode::SEE_OTHER => { self.body = None; match self.method { - Method::Get | Method::Head => {}, + Method::GET | Method::HEAD => {}, _ => { - self.method = Method::Get; + self.method = Method::GET; } } true }, - StatusCode::TemporaryRedirect | - StatusCode::PermanentRedirect => match self.body { + StatusCode::TEMPORARY_REDIRECT | + StatusCode::PERMANENT_REDIRECT => match self.body { Some(Some(_)) | None => true, Some(None) => false, }, @@ -530,12 +538,12 @@ impl Future for PendingRequest { }; if should_redirect { let loc = res.headers() - .get::() - .map(|loc| self.url.join(loc)); + .get(LOCATION) + .map(|loc| self.url.join(loc.to_str().expect(""))); if let Some(Ok(loc)) = loc { if self.client.referer { if let Some(referer) = make_referer(&loc, &self.url) { - self.headers.set(referer); + self.headers.insert(REFERER, referer); } } self.urls.push(self.url.clone()); @@ -553,19 +561,17 @@ impl Future for PendingRequest { remove_sensitive_headers(&mut self.headers, &self.url, &self.urls); debug!("redirecting to {:?} '{}'", self.method, self.url); let uri = to_uri(&self.url); - let mut req = ::hyper::Request::new( - self.method.clone(), - uri.clone() - ); + let body = match self.body { + Some(Some(ref body)) => ::hyper::Body::from(body.clone()), + _ => ::hyper::Body::empty(), + }; + let mut req = ::hyper::Request::builder() + .method(self.method.clone()) + .uri(uri.clone()) + .body(body) + .expect("valid request parts"); + *req.headers_mut() = self.headers.clone(); - if let Some(Some(ref body)) = self.body { - req.set_body(body.clone()); - } - if proxy::is_proxied(&self.client.proxies, &self.url) { - if uri.scheme() == Some("http") { - req.set_proxy(true); - } - } self.in_flight = self.client.hyper.request(req); continue; }, @@ -607,7 +613,7 @@ impl fmt::Debug for Pending { } } -fn make_referer(next: &Url, previous: &Url) -> Option { +fn make_referer(next: &Url, previous: &Url) -> Option { if next.scheme() == "http" && previous.scheme() == "https" { return None; } @@ -616,7 +622,7 @@ fn make_referer(next: &Url, previous: &Url) -> Option { let _ = referer.set_username(""); let _ = referer.set_password(None); referer.set_fragment(None); - Some(Referer::new(referer.into_string())) + referer.as_str().parse().ok() } // pub(crate) diff --git a/src/async_impl/decoder.rs b/src/async_impl/decoder.rs index 441c8cc..1ffc8ed 100644 --- a/src/async_impl/decoder.rs +++ b/src/async_impl/decoder.rs @@ -33,12 +33,12 @@ use tokio_io::AsyncRead; use tokio_io::io as async_io; use futures::{Async, Future, Poll, Stream}; use futures::stream::Concat2; -use hyper::StatusCode; +use hyper::{HeaderMap, StatusCode}; +use hyper::header::{CONTENT_ENCODING, CONTENT_LENGTH, TRANSFER_ENCODING, HeaderValue}; use serde::de::DeserializeOwned; use serde_json; use url::Url; -use header::{Headers, ContentEncoding, ContentLength, Encoding, TransferEncoding}; use super::{body, Body, Chunk}; use error; @@ -111,6 +111,13 @@ impl Decoder { inner: Inner::Pending(Pending::Gzip(ReadableChunks::new(body))) } } + + pub(crate) fn content_length(&self) -> Option { + match self.inner { + Inner::PlainText(ref body) => body.content_length(), + _ => None, + } + } } impl Stream for Decoder { @@ -407,31 +414,33 @@ impl ReadableChunks /// how to decode the content body of the request. /// /// Uses the correct variant by inspecting the Content-Encoding header. -pub fn detect(headers: &mut Headers, body: Body, check_gzip: bool) -> Decoder { +pub fn detect(headers: &mut HeaderMap, body: Body, check_gzip: bool) -> Decoder { if !check_gzip { return Decoder::plain_text(body); } let content_encoding_gzip: bool; let mut is_gzip = { content_encoding_gzip = headers - .get::() - .map_or(false, |encs| encs.contains(&Encoding::Gzip)); + .get_all(CONTENT_ENCODING) + .iter() + .fold(false, |acc, enc| acc || enc == HeaderValue::from_static("gzip")); content_encoding_gzip || headers - .get::() - .map_or(false, |encs| encs.contains(&Encoding::Gzip)) + .get_all(TRANSFER_ENCODING) + .iter() + .fold(false, |acc, enc| acc || enc == HeaderValue::from_static("gzip")) }; if is_gzip { - if let Some(content_length) = headers.get::() { - if content_length.0 == 0 { + if let Some(content_length) = headers.get(CONTENT_LENGTH) { + if content_length == "0" { warn!("GZipped response with content-length of 0"); is_gzip = false; } } } if content_encoding_gzip { - headers.remove::(); - headers.remove::(); + headers.remove(CONTENT_ENCODING); + headers.remove(CONTENT_LENGTH); } if is_gzip { Decoder::gzip(body) diff --git a/src/async_impl/request.rs b/src/async_impl/request.rs index 42bc401..cfbaa4e 100644 --- a/src/async_impl/request.rs +++ b/src/async_impl/request.rs @@ -1,19 +1,22 @@ use std::fmt; +use base64::{encode}; +use mime::{self}; use serde::Serialize; use serde_json; use serde_urlencoded; use super::body::{self, Body}; use super::client::{Client, Pending, pending_err}; -use header::{ContentType, Headers}; +use header::{CONTENT_TYPE, HeaderMap, HeaderName, HeaderValue}; +use http::HttpTryFrom; use {Method, Url}; /// A request which can be executed with `Client::execute()`. pub struct Request { method: Method, url: Url, - headers: Headers, + headers: HeaderMap, body: Option, } @@ -31,7 +34,7 @@ impl Request { Request { method, url, - headers: Headers::new(), + headers: HeaderMap::new(), body: None, } } @@ -62,13 +65,13 @@ impl Request { /// Get the headers. #[inline] - pub fn headers(&self) -> &Headers { + pub fn headers(&self) -> &HeaderMap { &self.headers } /// Get a mutable reference to the headers. #[inline] - pub fn headers_mut(&mut self) -> &mut Headers { + pub fn headers_mut(&mut self) -> &mut HeaderMap { &mut self.headers } @@ -87,21 +90,32 @@ impl Request { impl RequestBuilder { /// Add a `Header` to this Request. - pub fn header(&mut self, header: H) -> &mut RequestBuilder + pub fn header(&mut self, key: K, value: V) -> &mut RequestBuilder where - H: ::header::Header, + HeaderName: HttpTryFrom, + HeaderValue: HttpTryFrom, { if let Some(req) = request_mut(&mut self.request, &self.err) { - req.headers_mut().set(header); + match >::try_from(key) { + Ok(key) => { + match >::try_from(value) { + Ok(value) => { req.headers_mut().append(key, value); } + Err(e) => self.err = Some(::error::from(e.into())), + } + }, + Err(e) => self.err = Some(::error::from(e.into())), + }; } self } /// Add a set of Headers to the existing ones on this Request. /// /// The headers will be merged in to any already set. - pub fn headers(&mut self, headers: ::header::Headers) -> &mut RequestBuilder { + pub fn headers(&mut self, headers: ::header::HeaderMap) -> &mut RequestBuilder { if let Some(req) = request_mut(&mut self.request, &self.err) { - req.headers_mut().extend(headers.iter()); + for (key, value) in headers.iter() { + req.headers_mut().insert(key, value.clone()); + } } self } @@ -112,10 +126,10 @@ impl RequestBuilder { U: Into, P: Into, { - self.header(::header::Authorization(::header::Basic { - username: username.into(), - password: password.map(|p| p.into()), - })) + let username = username.into(); + let password = password.map(|p| p.into()).unwrap_or(String::new()); + let header_value = format!("basic {}:{}", username, encode(&password)); + self.header(::header::AUTHORIZATION, HeaderValue::from_str(header_value.as_str()).expect("")) } /// Set the request body. @@ -162,7 +176,7 @@ impl RequestBuilder { if let Some(req) = request_mut(&mut self.request, &self.err) { match serde_urlencoded::to_string(form) { Ok(body) => { - req.headers_mut().set(ContentType::form_url_encoded()); + req.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_str(mime::APPLICATION_WWW_FORM_URLENCODED.as_ref()).expect("")); *req.body_mut() = Some(body.into()); }, Err(err) => self.err = Some(::error::from(err)), @@ -181,7 +195,7 @@ impl RequestBuilder { if let Some(req) = request_mut(&mut self.request, &self.err) { match serde_json::to_vec(json) { Ok(body) => { - req.headers_mut().set(ContentType::json()); + req.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_str(mime::APPLICATION_JSON.as_ref()).expect("")); *req.body_mut() = Some(body.into()); }, Err(err) => self.err = Some(::error::from(err)), @@ -274,7 +288,7 @@ pub fn builder(client: Client, req: ::Result) -> RequestBuilder { } #[inline] -pub fn pieces(req: Request) -> (Method, Url, Headers, Option) { +pub fn pieces(req: Request) -> (Method, Url, HeaderMap, Option) { (req.method, req.url, req.headers, req.body) } @@ -282,12 +296,10 @@ pub fn pieces(req: Request) -> (Method, Url, Headers, Option) { mod tests { use super::Client; use std::collections::BTreeMap; - use tokio_core::reactor::Core; #[test] fn add_query_append() { - let mut core = Core::new().unwrap(); - let client = Client::new(&core.handle()); + let client = Client::new(); let some_url = "https://google.com/"; let mut r = client.get(some_url); @@ -300,8 +312,7 @@ mod tests { #[test] fn add_query_append_same() { - let mut core = Core::new().unwrap(); - let client = Client::new(&core.handle()); + let client = Client::new(); let some_url = "https://google.com/"; let mut r = client.get(some_url); @@ -319,8 +330,7 @@ mod tests { qux: i32, } - let mut core = Core::new().unwrap(); - let client = Client::new(&core.handle()); + let client = Client::new(); let some_url = "https://google.com/"; let mut r = client.get(some_url); @@ -338,8 +348,7 @@ mod tests { params.insert("foo", "bar"); params.insert("qux", "three"); - let mut core = Core::new().unwrap(); - let client = Client::new(&core.handle()); + let client = Client::new(); let some_url = "https://google.com/"; let mut r = client.get(some_url); diff --git a/src/async_impl/response.rs b/src/async_impl/response.rs index 0d14b57..9627045 100644 --- a/src/async_impl/response.rs +++ b/src/async_impl/response.rs @@ -13,7 +13,7 @@ use serde::de::DeserializeOwned; use serde_json; use url::Url; -use header::{Headers, ContentEncoding, ContentLength, Encoding, TransferEncoding}; +use hyper::header::{HeaderMap, CONTENT_ENCODING, CONTENT_LENGTH, TRANSFER_ENCODING}; use super::{decoder, body, Body, Chunk, Decoder}; use error; @@ -21,7 +21,7 @@ use error; /// A Response to a submitted `Request`. pub struct Response { status: StatusCode, - headers: Headers, + headers: HeaderMap, url: Url, body: Decoder, } @@ -41,13 +41,13 @@ impl Response { /// Get the `Headers` of this `Response`. #[inline] - pub fn headers(&self) -> &Headers { + pub fn headers(&self) -> &HeaderMap { &self.headers } /// Get a mutable reference to the `Headers` of this `Response`. #[inline] - pub fn headers_mut(&mut self) -> &mut Headers { + pub fn headers_mut(&mut self) -> &mut HeaderMap { &mut self.headers } @@ -99,7 +99,7 @@ impl Response { /// // it could be any status between 400...599 /// assert_eq!( /// err.status(), - /// Some(reqwest::StatusCode::BadRequest) + /// Some(reqwest::StatusCode::BAD_REQUEST) /// ); /// } /// } @@ -152,10 +152,10 @@ impl fmt::Debug for Json { // pub(crate) -pub fn new(mut res: ::hyper::client::Response, url: Url, gzip: bool) -> Response { +pub fn new(mut res: ::hyper::Response<::hyper::Body>, url: Url, gzip: bool) -> Response { let status = res.status(); - let mut headers = mem::replace(res.headers_mut(), Headers::new()); - let decoder = decoder::detect(&mut headers, body::wrap(res.body()), gzip); + let mut headers = mem::replace(res.headers_mut(), HeaderMap::new()); + let decoder = decoder::detect(&mut headers, body::wrap(res.into_body()), gzip); debug!("Response: '{}' for {}", status, url); Response { status: status, diff --git a/src/body.rs b/src/body.rs index e31653e..e7ca538 100644 --- a/src/body.rs +++ b/src/body.rs @@ -3,9 +3,9 @@ use std::fmt; use std::io::{self, Cursor, Read}; use bytes::Bytes; -use hyper::{self, Chunk}; +use hyper::{self}; -use {async_impl, wait}; +use {async_impl}; /// The body of a `Request`. /// @@ -184,7 +184,7 @@ impl Read for Reader { pub struct Sender { body: (Box, Option), - tx: wait::WaitSink<::futures::sync::mpsc::Sender>>, + tx: hyper::body::Sender, } impl Sender { @@ -201,13 +201,8 @@ impl Sender { Ok(0) => return Ok(()), Ok(n) => { unsafe { buf.advance_mut(n); } - if let Err(e) = tx.send(Ok(buf.take().freeze().into())) { - if let wait::Waited::Err(_) = e { - let epipe = io::Error::new(io::ErrorKind::BrokenPipe, "broken pipe"); - return Err(::error::from(epipe)); - } else { - return Err(::error::timedout(None)); - } + if let Err(_) = tx.send_data(buf.take().freeze().into()) { + return Err(::error::timedout(None)); } if buf.remaining_mut() == 0 { buf.reserve(8192); @@ -215,7 +210,7 @@ impl Sender { } Err(e) => { let ret = io::Error::new(e.kind(), e.to_string()); - let _ = tx.send(Err(e.into())); + tx.abort(); return Err(::error::from(ret)); } } @@ -227,10 +222,10 @@ impl Sender { pub fn async(body: Body) -> (Option, async_impl::Body, Option) { match body.kind { Kind::Reader(read, len) => { - let (tx, rx) = hyper::Body::pair(); + let (tx, rx) = hyper::Body::channel(); let tx = Sender { body: (read, len), - tx: wait::sink(tx, None), + tx: tx, }; (Some(tx), async_impl::body::wrap(rx), len) }, diff --git a/src/client.rs b/src/client.rs index 11f154d..28320c0 100644 --- a/src/client.rs +++ b/src/client.rs @@ -174,8 +174,8 @@ impl ClientBuilder { /// ```rust /// use reqwest::header; /// # fn build_client() -> Result<(), Box> { - /// let mut headers = header::Headers::new(); - /// headers.set(header::Authorization("secret".to_string())); + /// let mut headers = header::HeaderMap::new(); + /// headers.insert(header::AUTHORIZATION, header::HeaderValue::from_static("secret")); /// /// // get a client builder /// let client = reqwest::Client::builder() @@ -191,8 +191,8 @@ impl ClientBuilder { /// ```rust /// use reqwest::header; /// # fn build_client() -> Result<(), Box> { - /// let mut headers = header::Headers::new(); - /// headers.set(header::Authorization("secret".to_string())); + /// let mut headers = header::HeaderMap::new(); + /// headers.insert(header::AUTHORIZATION, header::HeaderValue::from_static("secret")); /// /// // get a client builder /// let client = reqwest::Client::builder() @@ -200,13 +200,13 @@ impl ClientBuilder { /// .build()?; /// let res = client /// .get("https://www.rust-lang.org") - /// .header(header::Authorization("token".to_string())) + /// .header(header::AUTHORIZATION, "token") /// .send()?; /// # Ok(()) /// # } /// ``` #[inline] - pub fn default_headers(&mut self, headers: header::Headers) -> &mut ClientBuilder { + pub fn default_headers(&mut self, headers: header::HeaderMap) -> &mut ClientBuilder { self.inner.default_headers(headers); self } @@ -287,7 +287,7 @@ impl Client { /// /// This method fails whenever supplied `Url` cannot be parsed. pub fn get(&self, url: U) -> RequestBuilder { - self.request(Method::Get, url) + self.request(Method::GET, url) } /// Convenience method to make a `POST` request to a URL. @@ -296,7 +296,7 @@ impl Client { /// /// This method fails whenever supplied `Url` cannot be parsed. pub fn post(&self, url: U) -> RequestBuilder { - self.request(Method::Post, url) + self.request(Method::POST, url) } /// Convenience method to make a `PUT` request to a URL. @@ -305,7 +305,7 @@ impl Client { /// /// This method fails whenever supplied `Url` cannot be parsed. pub fn put(&self, url: U) -> RequestBuilder { - self.request(Method::Put, url) + self.request(Method::PUT, url) } /// Convenience method to make a `PATCH` request to a URL. @@ -314,7 +314,7 @@ impl Client { /// /// This method fails whenever supplied `Url` cannot be parsed. pub fn patch(&self, url: U) -> RequestBuilder { - self.request(Method::Patch, url) + self.request(Method::PATCH, url) } /// Convenience method to make a `DELETE` request to a URL. @@ -323,7 +323,7 @@ impl Client { /// /// This method fails whenever supplied `Url` cannot be parsed. pub fn delete(&self, url: U) -> RequestBuilder { - self.request(Method::Delete, url) + self.request(Method::DELETE, url) } /// Convenience method to make a `HEAD` request to a URL. @@ -332,7 +332,7 @@ impl Client { /// /// This method fails whenever supplied `Url` cannot be parsed. pub fn head(&self, url: U) -> RequestBuilder { - self.request(Method::Head, url) + self.request(Method::HEAD, url) } /// Start building a `Request` with the `Method` and `Url`. @@ -412,22 +412,21 @@ impl ClientHandle { let mut builder = async_impl::client::take_builder(&mut builder.inner); let (tx, rx) = mpsc::unbounded(); let (spawn_tx, spawn_rx) = oneshot::channel::<::Result<()>>(); - let handle = try_!(thread::Builder::new().name("reqwest-internal-sync-core".into()).spawn(move || { - use tokio_core::reactor::Core; + let handle = try_!(thread::Builder::new().name("reqwest-internal-sync-runtime".into()).spawn(move || { + use tokio::runtime::current_thread::Runtime; let built = (|| { - let core = try_!(Core::new()); - let handle = core.handle(); - let client = builder.build(&handle)?; - Ok((core, handle, client)) + let rt = try_!(Runtime::new()); + let client = builder.build()?; + Ok((rt, client)) })(); - let (mut core, handle, client) = match built { - Ok((a, b, c)) => { + let (mut rt, client) = match built { + Ok((rt, c)) => { if let Err(_) = spawn_tx.send(Ok(())) { return; } - (a, b, c) + (rt, c) }, Err(e) => { let _ = spawn_tx.send(Err(e)); @@ -435,19 +434,22 @@ impl ClientHandle { } }; - let work = rx.for_each(|(req, tx)| { + let work = rx.for_each(move |(req, tx)| { let tx: oneshot::Sender<::Result> = tx; let task = client.execute(req) .then(move |x| tx.send(x).map_err(|_| ())); - handle.spawn(task); + ::tokio::spawn(task); Ok(()) }); + // work is Future<(), ()>, and our closure will never return Err - let _ = core.run(work); + rt.spawn(work) + .run() + .expect("runtime unexpected error"); })); - wait::timeout(spawn_rx, timeout.0).expect("core thread cancelled")?; + wait::timeout(spawn_rx, timeout.0).expect("runtime thread cancelled")?; let inner_handle = Arc::new(InnerClientHandle { tx: Some(tx), diff --git a/src/connect.rs b/src/connect.rs index adec0fb..b0d6eb4 100644 --- a/src/connect.rs +++ b/src/connect.rs @@ -1,10 +1,10 @@ use bytes::{Buf, BufMut, IntoBuf}; use futures::{Async, Future, Poll}; -use hyper::client::{HttpConnector, Service}; -use hyper::Uri; +use http::uri::Scheme; +use hyper::client::{HttpConnector}; +use hyper::client::connect::{Connect, Connected, Destination}; use hyper_tls::{HttpsConnector, MaybeHttpsStream}; use native_tls::TlsConnector; -use tokio_core::reactor::Handle; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_tls::{TlsConnectorExt, TlsStream}; @@ -22,8 +22,8 @@ pub struct Connector { } impl Connector { - pub fn new(threads: usize, tls: TlsConnector, proxies: Arc>, handle: &Handle) -> Connector { - let mut http = HttpConnector::new(threads, handle); + pub fn new(threads: usize, tls: TlsConnector, proxies: Arc>) -> Connector { + let mut http = HttpConnector::new(threads); http.enforce_http(false); let https = HttpsConnector::from((http, tls.clone())); @@ -39,41 +39,53 @@ impl Connector { } } -impl Service for Connector { - type Request = Uri; - type Response = Conn; +impl Connect for Connector { + type Transport = Conn; type Error = io::Error; type Future = Connecting; - fn call(&self, uri: Uri) -> Self::Future { + fn connect(&self, dst: Destination) -> Self::Future { for prox in self.proxies.iter() { - if let Some(puri) = proxy::intercept(prox, &uri) { - trace!("proxy({:?}) intercepts {:?}", puri, uri); - if uri.scheme() == Some("https") { - let host = uri.host().unwrap().to_owned(); - let port = uri.port().unwrap_or(443); + if let Some(puri) = proxy::intercept(prox, &dst) { + trace!("proxy({:?}) intercepts {:?}", puri, dst); + let mut ndst = dst.clone(); + let new_scheme = puri + .scheme_part() + .map(Scheme::as_str) + .unwrap_or("http"); + ndst.set_scheme(new_scheme) + .expect("proxy target scheme should be valid"); + + ndst.set_host(puri.host().expect("proxy target should have host")) + .expect("proxy target host should be valid"); + + ndst.set_port(puri.port()); + + if dst.scheme() == "https" { + let host = dst.host().to_owned(); + let port = dst.port().unwrap_or(443); let tls = self.tls.clone(); - return Box::new(self.https.call(puri).and_then(move |conn| { + return Box::new(self.https.connect(ndst).and_then(move |(conn, connected)| { trace!("tunneling HTTPS over proxy"); tunnel(conn, host.clone(), port) .and_then(move |tunneled| { tls.connect_async(&host, tunneled) .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) }) - .map(|io| Conn::Proxied(io)) + .map(|io| (Conn::Proxied(io), connected.proxy(true))) })); } - return Box::new(self.https.call(puri).map(|io| Conn::Normal(io))); + return Box::new(self.https.connect(ndst).map(|(io, connected)| (Conn::Normal(io), connected.proxy(true)))); } } - Box::new(self.https.call(uri).map(|io| Conn::Normal(io))) + Box::new(self.https.connect(dst).map(|(io, connected)| (Conn::Normal(io), connected))) } } -type HttpStream = ::Response; +type HttpStream = ::Transport; type HttpsStream = MaybeHttpsStream; -pub type Connecting = Box>; +pub type Connecting = Box + Send>; pub enum Conn { Normal(HttpsStream), @@ -214,8 +226,8 @@ mod tests { use std::net::TcpListener; use std::thread; use futures::Future; - use tokio_core::reactor::Core; - use tokio_core::net::TcpStream; + use tokio::runtime::current_thread::Runtime; + use tokio::net::TcpStream; use super::tunnel; @@ -251,44 +263,44 @@ mod tests { fn test_tunnel() { let addr = mock_tunnel!(); - let mut core = Core::new().unwrap(); - let work = TcpStream::connect(&addr, &core.handle()); + let mut rt = Runtime::new().unwrap(); + let work = TcpStream::connect(&addr); let host = addr.ip().to_string(); let port = addr.port(); let work = work.and_then(|tcp| { tunnel(tcp, host, port) }); - core.run(work).unwrap(); + rt.block_on(work).unwrap(); } #[test] fn test_tunnel_eof() { let addr = mock_tunnel!(b"HTTP/1.1 200 OK"); - let mut core = Core::new().unwrap(); - let work = TcpStream::connect(&addr, &core.handle()); + let mut rt = Runtime::new().unwrap(); + let work = TcpStream::connect(&addr); let host = addr.ip().to_string(); let port = addr.port(); let work = work.and_then(|tcp| { tunnel(tcp, host, port) }); - core.run(work).unwrap_err(); + rt.block_on(work).unwrap_err(); } #[test] fn test_tunnel_bad_response() { let addr = mock_tunnel!(b"foo bar baz hallo"); - let mut core = Core::new().unwrap(); - let work = TcpStream::connect(&addr, &core.handle()); + let mut rt = Runtime::new().unwrap(); + let work = TcpStream::connect(&addr); let host = addr.ip().to_string(); let port = addr.port(); let work = work.and_then(|tcp| { tunnel(tcp, host, port) }); - core.run(work).unwrap_err(); + rt.block_on(work).unwrap_err(); } } diff --git a/src/error.rs b/src/error.rs index 80eb12e..1ac9dd8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -112,6 +112,7 @@ impl Error { pub fn get_ref(&self) -> Option<&(StdError + Send + Sync + 'static)> { match self.kind { Kind::Http(ref e) => Some(e), + Kind::Hyper(ref e) => Some(e), Kind::Url(ref e) => Some(e), Kind::Tls(ref e) => Some(e), Kind::Io(ref e) => Some(e), @@ -129,6 +130,7 @@ impl Error { pub fn is_http(&self) -> bool { match self.kind { Kind::Http(_) => true, + Kind::Hyper(_) => true, _ => false, } } @@ -190,6 +192,7 @@ impl fmt::Display for Error { } match self.kind { Kind::Http(ref e) => fmt::Display::fmt(e, f), + Kind::Hyper(ref e) => fmt::Display::fmt(e, f), Kind::Url(ref e) => fmt::Display::fmt(e, f), Kind::Tls(ref e) => fmt::Display::fmt(e, f), Kind::Io(ref e) => fmt::Display::fmt(e, f), @@ -213,6 +216,7 @@ impl StdError for Error { fn description(&self) -> &str { match self.kind { Kind::Http(ref e) => e.description(), + Kind::Hyper(ref e) => e.description(), Kind::Url(ref e) => e.description(), Kind::Tls(ref e) => e.description(), Kind::Io(ref e) => e.description(), @@ -228,6 +232,7 @@ impl StdError for Error { fn cause(&self) -> Option<&StdError> { match self.kind { Kind::Http(ref e) => e.cause(), + Kind::Hyper(ref e) => e.cause(), Kind::Url(ref e) => e.cause(), Kind::Tls(ref e) => e.cause(), Kind::Io(ref e) => e.cause(), @@ -245,7 +250,8 @@ impl StdError for Error { #[derive(Debug)] pub enum Kind { - Http(::hyper::Error), + Http(::http::Error), + Hyper(::hyper::Error), Url(::url::ParseError), Tls(::native_tls::Error), Io(io::Error), @@ -258,13 +264,18 @@ pub enum Kind { } +impl From<::http::Error> for Kind { + #[inline] + fn from(err: ::http::Error) -> Kind { + Kind::Http(err) + } +} + impl From<::hyper::Error> for Kind { #[inline] fn from(err: ::hyper::Error) -> Kind { match err { - ::hyper::Error::Io(err) => Kind::Io(err), - //::hyper::Error::Uri(err) => Kind::Url(err), - other => Kind::Http(other), + other => Kind::Hyper(other), } } } @@ -430,20 +441,6 @@ pub fn server_error(url: Url, status: StatusCode) -> Error { mod tests { use super::*; - #[test] - fn test_error_get_ref_downcasts() { - let err: Error = from(::hyper::Error::Status); - let cause = err.get_ref() - .unwrap() - .downcast_ref::<::hyper::Error>() - .unwrap(); - - match cause { - &::hyper::Error::Status => (), - _ => panic!("unexpected downcast: {:?}", cause), - } - } - #[test] fn test_cause_chain() { #[derive(Debug)] @@ -476,9 +473,6 @@ mod tests { } } - let err = from(::hyper::Error::Status); - assert!(err.cause().is_none()); - let root = Chain(None::); let io = ::std::io::Error::new(::std::io::ErrorKind::Other, root); let err = Error { kind: Kind::Io(io), url: None }; diff --git a/src/into_url.rs b/src/into_url.rs index aee4c2f..80de1bd 100644 --- a/src/into_url.rs +++ b/src/into_url.rs @@ -36,7 +36,3 @@ impl<'a> PolyfillTryInto for &'a String { pub fn to_uri(url: &Url) -> ::hyper::Uri { url.as_str().parse().expect("a parsed Url should always be a valid Uri") } - -pub fn to_url(uri: &::hyper::Uri) -> Url { - uri.as_ref().parse().expect("reqwest Uris should only ever come from Urls") -} diff --git a/src/lib.rs b/src/lib.rs index ea678bd..399f6e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -124,15 +124,18 @@ //! [serde]: http://serde.rs //! [cookiejar_issue]: https://github.com/seanmonstar/reqwest/issues/14 +extern crate base64; extern crate bytes; extern crate encoding_rs; #[macro_use] extern crate futures; +extern crate http; extern crate hyper; extern crate hyper_tls; #[macro_use] extern crate log; extern crate libflate; +extern crate mime; extern crate mime_guess; extern crate native_tls; extern crate serde; @@ -141,14 +144,13 @@ extern crate serde; extern crate serde_derive; extern crate serde_json; extern crate serde_urlencoded; -extern crate tokio_core; +extern crate tokio; extern crate tokio_io; extern crate tokio_tls; extern crate url; extern crate uuid; pub use hyper::header; -pub use hyper::mime; pub use hyper::Method; pub use hyper::StatusCode; pub use url::Url; diff --git a/src/multipart_.rs b/src/multipart_.rs index 9ec7711..ae16987 100644 --- a/src/multipart_.rs +++ b/src/multipart_.rs @@ -4,8 +4,7 @@ use std::fs::File; use std::io::{self, Cursor, Read}; use std::path::Path; -use mime::Mime; -use mime_guess; +use mime_guess::{self, Mime}; use url::percent_encoding; use uuid::Uuid; diff --git a/src/proxy.rs b/src/proxy.rs index 9739cca..f657f1d 100644 --- a/src/proxy.rs +++ b/src/proxy.rs @@ -1,7 +1,7 @@ use std::fmt; use std::sync::Arc; -use hyper::Uri; +use hyper::client::connect::Destination; use {into_url, IntoUrl, Url}; /// Configuration of a proxy that a `Client` should pass requests to. @@ -128,36 +128,36 @@ impl Proxy { } } - fn proxies(&self, url: &Url) -> bool { - match self.intercept { - Intercept::All(..) => true, - Intercept::Http(..) => url.scheme() == "http", - Intercept::Https(..) => url.scheme() == "https", - Intercept::Custom(ref fun) => (fun.0)(url).is_some(), - } - } - - - fn intercept(&self, uri: &Uri) -> Option { + fn intercept(&self, uri: &D) -> Option<::hyper::Uri> { match self.intercept { Intercept::All(ref u) => Some(u.clone()), Intercept::Http(ref u) => { - if uri.scheme() == Some("http") { + if uri.scheme() == "http" { Some(u.clone()) } else { None } }, Intercept::Https(ref u) => { - if uri.scheme() == Some("https") { + if uri.scheme() == "https" { Some(u.clone()) } else { None } }, Intercept::Custom(ref fun) => { - (fun.0)(&into_url::to_url(uri)) - .map(|u| into_url::to_uri(&u)) + (fun.0)( + &format!( + "{}://{}{}{}", + uri.scheme(), + uri.host(), + uri.port().map(|_| ":").unwrap_or(""), + uri.port().map(|p| p.to_string()).unwrap_or(String::new()) + ) + .parse() + .expect("should be valid Url") + ) + .map(|u| into_url::to_uri(&u) ) }, } } @@ -165,9 +165,9 @@ impl Proxy { #[derive(Clone, Debug)] enum Intercept { - All(Uri), - Http(Uri), - Https(Uri), + All(::hyper::Uri), + Http(::hyper::Uri), + Https(::hyper::Uri), Custom(Custom), } @@ -182,20 +182,50 @@ impl fmt::Debug for Custom { // pub(crate) -pub fn intercept(proxy: &Proxy, uri: &Uri) -> Option { - proxy.intercept(uri) +/// A helper trait to allow testing `Proxy::intercept` without having to +/// construct `hyper::client::connect::Destination`s. +trait Dst { + fn scheme(&self) -> &str; + fn host(&self) -> &str; + fn port(&self) -> Option; } -pub fn is_proxied(proxies: &[Proxy], uri: &Url) -> bool { - proxies.iter().any(|p| p.proxies(uri)) +#[doc(hidden)] +impl Dst for Destination { + fn scheme(&self) -> &str { + Destination::scheme(self) + } + + fn host(&self) -> &str { + Destination::host(self) + } + + fn port(&self) -> Option { + Destination::port(self) + } +} + +pub fn intercept(proxy: &Proxy, uri: &Destination) -> Option<::http::Uri> { + proxy.intercept(uri) } #[cfg(test)] mod tests { use super::*; - fn uri(s: &str) -> Uri { - s.parse().unwrap() + impl Dst for Url { + fn scheme(&self) -> &str { + Url::scheme(self) + } + + fn host(&self) -> &str { + Url::host_str(self) + .expect("::host should have a str") + } + + fn port(&self) -> Option { + Url::port(self) + } } fn url(s: &str) -> Url { @@ -210,10 +240,8 @@ mod tests { let http = "http://hyper.rs"; let other = "https://hyper.rs"; - assert!(p.proxies(&url(http))); - assert_eq!(p.intercept(&uri(http)).unwrap(), target); - assert!(!p.proxies(&url(other))); - assert!(p.intercept(&uri(other)).is_none()); + assert_eq!(p.intercept(&url(http)).unwrap(), target); + assert!(p.intercept(&url(other)).is_none()); } #[test] @@ -224,10 +252,8 @@ mod tests { let http = "http://hyper.rs"; let other = "https://hyper.rs"; - assert!(!p.proxies(&url(http))); - assert!(p.intercept(&uri(http)).is_none()); - assert!(p.proxies(&url(other))); - assert_eq!(p.intercept(&uri(other)).unwrap(), target); + assert!(p.intercept(&url(http)).is_none()); + assert_eq!(p.intercept(&url(other)).unwrap(), target); } #[test] @@ -239,13 +265,9 @@ mod tests { let https = "https://hyper.rs"; let other = "x-youve-never-heard-of-me-mr-proxy://hyper.rs"; - assert!(p.proxies(&url(http))); - assert!(p.proxies(&url(https))); - assert!(p.proxies(&url(other))); - - assert_eq!(p.intercept(&uri(http)).unwrap(), target); - assert_eq!(p.intercept(&uri(https)).unwrap(), target); - assert_eq!(p.intercept(&uri(other)).unwrap(), target); + assert_eq!(p.intercept(&url(http)).unwrap(), target); + assert_eq!(p.intercept(&url(https)).unwrap(), target); + assert_eq!(p.intercept(&url(other)).unwrap(), target); } @@ -267,29 +289,9 @@ mod tests { let https = "https://hyper.rs"; let other = "x-youve-never-heard-of-me-mr-proxy://seanmonstar.com"; - assert!(p.proxies(&url(http))); - assert!(p.proxies(&url(https))); - assert!(!p.proxies(&url(other))); - - assert_eq!(p.intercept(&uri(http)).unwrap(), target2); - assert_eq!(p.intercept(&uri(https)).unwrap(), target1); - assert!(p.intercept(&uri(other)).is_none()); - } - - #[test] - fn test_is_proxied() { - let proxies = vec![ - Proxy::http("http://example.domain").unwrap(), - Proxy::https("http://other.domain").unwrap(), - ]; - - let http = "http://hyper.rs".parse().unwrap(); - let https = "https://hyper.rs".parse().unwrap(); - let other = "x-other://hyper.rs".parse().unwrap(); - - assert!(is_proxied(&proxies, &http)); - assert!(is_proxied(&proxies, &https)); - assert!(!is_proxied(&proxies, &other)); + assert_eq!(p.intercept(&url(http)).unwrap(), target2); + assert_eq!(p.intercept(&url(https)).unwrap(), target1); + assert!(p.intercept(&url(other)).is_none()); } } diff --git a/src/redirect.rs b/src/redirect.rs index 543987a..0ba589c 100644 --- a/src/redirect.rs +++ b/src/redirect.rs @@ -1,6 +1,6 @@ use std::fmt; -use hyper::header::Headers; +use header::HeaderMap; use hyper::StatusCode; use Url; @@ -228,15 +228,15 @@ pub fn check_redirect( .inner } -pub fn remove_sensitive_headers(headers: &mut Headers, next: &Url, previous: &[Url]) { +pub fn remove_sensitive_headers(headers: &mut HeaderMap, next: &Url, previous: &[Url]) { if let Some(previous) = previous.last() { let cross_host = next.host_str() != previous.host_str() || next.port_or_known_default() != previous.port_or_known_default(); if cross_host { - headers.remove_raw("authorization"); - headers.remove_raw("cookie"); - headers.remove_raw("cookie2"); - headers.remove_raw("www-authenticate"); + headers.remove("authorization"); + headers.remove("cookie"); + headers.remove("cookie2"); + headers.remove("www-authenticate"); } } } @@ -268,14 +268,14 @@ fn test_redirect_policy_limit() { .collect::>(); assert_eq!( - check_redirect(&policy, StatusCode::Found, &next, &previous), + check_redirect(&policy, StatusCode::FOUND, &next, &previous), Action::Follow ); previous.push(Url::parse("http://a.b.d/e/33").unwrap()); assert_eq!( - check_redirect(&policy, StatusCode::Found, &next, &previous), + check_redirect(&policy, StatusCode::FOUND, &next, &previous), Action::TooManyRedirects ); } @@ -292,27 +292,25 @@ fn test_redirect_policy_custom() { let next = Url::parse("http://bar/baz").unwrap(); assert_eq!( - check_redirect(&policy, StatusCode::Found, &next, &[]), + check_redirect(&policy, StatusCode::FOUND, &next, &[]), Action::Follow ); let next = Url::parse("http://foo/baz").unwrap(); assert_eq!( - check_redirect(&policy, StatusCode::Found, &next, &[]), + check_redirect(&policy, StatusCode::FOUND, &next, &[]), Action::Stop ); } #[test] fn test_remove_sensitive_headers() { - use hyper::header::{Accept, Authorization, Cookie}; + use hyper::header::{ACCEPT, AUTHORIZATION, COOKIE, HeaderValue}; - let mut headers = Headers::new(); - headers.set(Accept::star()); - headers.set(Authorization("let me in".to_owned())); - let mut cookie = Cookie::new(); - cookie.set("foo", "bar"); - headers.set(cookie); + let mut headers = HeaderMap::new(); + headers.insert(ACCEPT, HeaderValue::from_static("*/*")); + headers.insert(AUTHORIZATION, HeaderValue::from_static("let me in")); + headers.insert(COOKIE, HeaderValue::from_static("foo=bar")); let next = Url::parse("http://initial-domain.com/path").unwrap(); let mut prev = vec![Url::parse("http://initial-domain.com/new_path").unwrap()]; @@ -322,8 +320,8 @@ fn test_remove_sensitive_headers() { assert_eq!(headers, filtered_headers); prev.push(Url::parse("http://new-domain.com/path").unwrap()); - filtered_headers.remove::>(); - filtered_headers.remove::(); + filtered_headers.remove(AUTHORIZATION); + filtered_headers.remove(COOKIE); remove_sensitive_headers(&mut headers, &next, &prev); assert_eq!(headers, filtered_headers); diff --git a/src/request.rs b/src/request.rs index 44c5def..d7bac6c 100644 --- a/src/request.rs +++ b/src/request.rs @@ -1,12 +1,13 @@ use std::fmt; -use hyper::header::ContentType; +use base64::encode; use serde::Serialize; use serde_json; use serde_urlencoded; use body::{self, Body}; -use header::Headers; +use header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE}; +use http::HttpTryFrom; use {async_impl, Client, Method, Url}; /// A request which can be executed with `Client::execute()`. @@ -58,13 +59,13 @@ impl Request { /// Get the headers. #[inline] - pub fn headers(&self) -> &Headers { + pub fn headers(&self) -> &HeaderMap { self.inner.headers() } /// Get a mutable reference to the headers. #[inline] - pub fn headers_mut(&mut self) -> &mut Headers { + pub fn headers_mut(&mut self) -> &mut HeaderMap { self.inner.headers_mut() } @@ -85,22 +86,31 @@ impl RequestBuilder { /// Add a `Header` to this Request. /// /// ```rust - /// use reqwest::header::UserAgent; + /// use reqwest::header::USER_AGENT; /// /// # fn run() -> Result<(), Box<::std::error::Error>> { /// let client = reqwest::Client::new(); /// let res = client.get("https://www.rust-lang.org") - /// .header(UserAgent::new("foo")) + /// .header(USER_AGENT, "foo") /// .send()?; /// # Ok(()) /// # } /// ``` - pub fn header(&mut self, header: H) -> &mut RequestBuilder + pub fn header(&mut self, key: K, value: V) -> &mut RequestBuilder where - H: ::header::Header, + HeaderName: HttpTryFrom, + HeaderValue: HttpTryFrom, { if let Some(req) = request_mut(&mut self.request, &self.err) { - req.headers_mut().set(header); + match >::try_from(key) { + Ok(key) => { + match >::try_from(value) { + Ok(value) => { req.headers_mut().append(key, value); } + Err(e) => self.err = Some(::error::from(e.into())), + } + }, + Err(e) => self.err = Some(::error::from(e.into())), + }; } self } @@ -110,13 +120,13 @@ impl RequestBuilder { /// The headers will be merged in to any already set. /// /// ```rust - /// use reqwest::header::{Headers, UserAgent, ContentType}; + /// use reqwest::header::{HeaderMap, HeaderValue, USER_AGENT, CONTENT_TYPE}; /// # use std::fs; /// - /// fn construct_headers() -> Headers { - /// let mut headers = Headers::new(); - /// headers.set(UserAgent::new("reqwest")); - /// headers.set(ContentType::png()); + /// fn construct_headers() -> HeaderMap { + /// let mut headers = HeaderMap::new(); + /// headers.insert(USER_AGENT, HeaderValue::from_static("reqwest")); + /// headers.insert(CONTENT_TYPE, HeaderValue::from_static("image/png")); /// headers /// } /// @@ -130,9 +140,11 @@ impl RequestBuilder { /// # Ok(()) /// # } /// ``` - pub fn headers(&mut self, headers: ::header::Headers) -> &mut RequestBuilder { + pub fn headers(&mut self, headers: ::header::HeaderMap) -> &mut RequestBuilder { if let Some(req) = request_mut(&mut self.request, &self.err) { - req.headers_mut().extend(headers.iter()); + for (key, value) in headers.iter() { + req.headers_mut().insert(key, value.clone()); + } } self } @@ -153,10 +165,10 @@ impl RequestBuilder { U: Into, P: Into, { - self.header(::header::Authorization(::header::Basic { - username: username.into(), - password: password.map(|p| p.into()), - })) + let username = username.into(); + let password = password.map(|p| p.into()).unwrap_or(String::new()); + let header_value = format!("basic {}:{}", username, encode(&password)); + self.header(::header::AUTHORIZATION, HeaderValue::from_str(header_value.as_str()).expect("")) } /// Set the request body. @@ -283,7 +295,7 @@ impl RequestBuilder { if let Some(req) = request_mut(&mut self.request, &self.err) { match serde_urlencoded::to_string(form) { Ok(body) => { - req.headers_mut().set(ContentType::form_url_encoded()); + req.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_str(::mime::APPLICATION_WWW_FORM_URLENCODED.as_ref()).expect("")); *req.body_mut() = Some(body.into()); }, Err(err) => self.err = Some(::error::from(err)), @@ -321,7 +333,7 @@ impl RequestBuilder { if let Some(req) = request_mut(&mut self.request, &self.err) { match serde_json::to_vec(json) { Ok(body) => { - req.headers_mut().set(ContentType::json()); + req.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_str(::mime::APPLICATION_JSON.as_ref()).expect("")); *req.body_mut() = Some(body.into()); }, Err(err) => self.err = Some(::error::from(err)), @@ -333,7 +345,6 @@ impl RequestBuilder { /// Sends a multipart/form-data body. /// /// ``` - /// use reqwest::mime; /// # use reqwest::Error; /// /// # fn run() -> Result<(), Box> { @@ -352,10 +363,14 @@ impl RequestBuilder { /// See [`multipart`](multipart/) for more examples. pub fn multipart(&mut self, mut multipart: ::multipart::Form) -> &mut RequestBuilder { if let Some(req) = request_mut(&mut self.request, &self.err) { - req.headers_mut().set( - ::header::ContentType(format!("multipart/form-data; boundary={}", ::multipart_::boundary(&multipart)) - .parse().unwrap() - ) + req.headers_mut().insert( + ::header::CONTENT_TYPE, + HeaderValue::from_str( + format!( + "multipart/form-data; boundary={}", + ::multipart_::boundary(&multipart) + ).as_str() + ).expect("") ); *req.body_mut() = Some(match ::multipart_::compute_length(&mut multipart) { Some(length) => Body::sized(::multipart_::reader(multipart), length), @@ -450,13 +465,13 @@ pub fn builder(client: Client, req: ::Result) -> RequestBuilder { #[inline] pub fn async(req: Request) -> (async_impl::Request, Option) { - use header::ContentLength; + use header::CONTENT_LENGTH; let mut req_async = req.inner; let body = req.body.and_then(|body| { let (tx, body, len) = body::async(body); if let Some(len) = len { - req_async.headers_mut().set(ContentLength(len)); + req_async.headers_mut().insert(CONTENT_LENGTH, HeaderValue::from_str(len.to_string().as_str()).expect("")); } *req_async.body_mut() = Some(body); tx @@ -467,7 +482,7 @@ pub fn async(req: Request) -> (async_impl::Request, Option) { #[cfg(test)] mod tests { use {body, Client, Method}; - use header::{Host, Headers, ContentType}; + use header::{HOST, HeaderMap, HeaderValue, CONTENT_TYPE}; use std::collections::{BTreeMap, HashMap}; use serde_json; use serde_urlencoded; @@ -478,7 +493,7 @@ mod tests { let some_url = "https://google.com/"; let r = client.get(some_url).build().unwrap(); - assert_eq!(r.method(), &Method::Get); + assert_eq!(r.method(), &Method::GET); assert_eq!(r.url().as_str(), some_url); } @@ -488,7 +503,7 @@ mod tests { let some_url = "https://google.com/"; let r = client.head(some_url).build().unwrap(); - assert_eq!(r.method(), &Method::Head); + assert_eq!(r.method(), &Method::HEAD); assert_eq!(r.url().as_str(), some_url); } @@ -498,7 +513,7 @@ mod tests { let some_url = "https://google.com/"; let r = client.post(some_url).build().unwrap(); - assert_eq!(r.method(), &Method::Post); + assert_eq!(r.method(), &Method::POST); assert_eq!(r.url().as_str(), some_url); } @@ -508,7 +523,7 @@ mod tests { let some_url = "https://google.com/"; let r = client.put(some_url).build().unwrap(); - assert_eq!(r.method(), &Method::Put); + assert_eq!(r.method(), &Method::PUT); assert_eq!(r.url().as_str(), some_url); } @@ -518,7 +533,7 @@ mod tests { let some_url = "https://google.com/"; let r = client.patch(some_url).build().unwrap(); - assert_eq!(r.method(), &Method::Patch); + assert_eq!(r.method(), &Method::PATCH); assert_eq!(r.url().as_str(), some_url); } @@ -528,7 +543,7 @@ mod tests { let some_url = "https://google.com/"; let r = client.delete(some_url).build().unwrap(); - assert_eq!(r.method(), &Method::Delete); + assert_eq!(r.method(), &Method::DELETE); assert_eq!(r.url().as_str(), some_url); } @@ -538,13 +553,13 @@ mod tests { let some_url = "https://google.com/"; let mut r = client.post(some_url); - let header = Host::new("google.com", None); + let header = HeaderValue::from_static("google.com"); // Add a copy of the header to the request builder - let r = r.header(header.clone()).build().unwrap(); + let r = r.header(HOST, header.clone()).build().unwrap(); // then check it was actually added - assert_eq!(r.headers().get::(), Some(&header)); + assert_eq!(r.headers().get(HOST), Some(&header)); } #[test] @@ -553,10 +568,10 @@ mod tests { let some_url = "https://google.com/"; let mut r = client.post(some_url); - let header = Host::new("google.com", None); + let header = HeaderValue::from_static("google.com"); - let mut headers = Headers::new(); - headers.set(header); + let mut headers = HeaderMap::new(); + headers.insert(HOST, header); // Add a copy of the headers to the request builder let r = r.headers(headers.clone()).build().unwrap(); @@ -653,8 +668,7 @@ mod tests { let mut r = r.form(&form_data).build().unwrap(); // Make sure the content type was set - assert_eq!(r.headers().get::(), - Some(&ContentType::form_url_encoded())); + assert_eq!(r.headers().get(CONTENT_TYPE).unwrap(), &"application/x-www-form-urlencoded"); let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap(); @@ -674,7 +688,7 @@ mod tests { let mut r = r.json(&json_data).build().unwrap(); // Make sure the content type was set - assert_eq!(r.headers().get::(), Some(&ContentType::json())); + assert_eq!(r.headers().get(CONTENT_TYPE).unwrap(), &"application/json"); let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap(); diff --git a/src/response.rs b/src/response.rs index 9058aad..79c6c9a 100644 --- a/src/response.rs +++ b/src/response.rs @@ -6,17 +6,19 @@ use std::borrow::Cow; use encoding_rs::{Encoding, UTF_8}; use futures::{Async, Poll, Stream}; +use mime::Mime; use serde::de::DeserializeOwned; use serde_json; use client::KeepCoreThreadAlive; -use header::Headers; +use hyper::header::HeaderMap; use {async_impl, StatusCode, Url, wait}; /// A Response to a submitted `Request`. pub struct Response { inner: async_impl::Response, body: async_impl::ReadableChunks, + content_length: Option, _thread_handle: KeepCoreThreadAlive, } @@ -70,8 +72,8 @@ impl Response { /// .body("possibly too large") /// .send()?; /// match resp.status() { - /// StatusCode::Ok => println!("success!"), - /// StatusCode::PayloadTooLarge => { + /// StatusCode::OK => println!("success!"), + /// StatusCode::PAYLOAD_TOO_LARGE => { /// println!("Request payload is too large!"); /// } /// s => println!("Received response status: {:?}", s), @@ -93,14 +95,15 @@ impl Response { /// ```rust /// # use std::io::{Read, Write}; /// # use reqwest::Client; - /// # use reqwest::header::ContentLength; + /// # use reqwest::header::CONTENT_LENGTH; /// # /// # fn run() -> Result<(), Box<::std::error::Error>> { /// let client = Client::new(); /// let mut resp = client.head("http://httpbin.org/bytes/3000").send()?; /// if resp.status().is_success() { - /// let len = resp.headers().get::() - /// .map(|ct_len| **ct_len) + /// let len = resp.headers().get(CONTENT_LENGTH) + /// .and_then(|ct_len| ct_len.to_str().ok()) + /// .and_then(|ct_len| ct_len.parse().ok()) /// .unwrap_or(0); /// // limit 1mb response /// if len <= 1_000_000 { @@ -115,7 +118,7 @@ impl Response { /// # } /// ``` #[inline] - pub fn headers(&self) -> &Headers { + pub fn headers(&self) -> &HeaderMap { self.inner.headers() } @@ -189,14 +192,21 @@ impl Response { /// This consumes the body. Trying to read more, or use of `response.json()` /// will return empty values. pub fn text(&mut self) -> ::Result { - let len = self.headers().get::<::header::ContentLength>() - .map(|ct_len| **ct_len) - .unwrap_or(0); + let len = self.content_length.unwrap_or(0); let mut content = Vec::with_capacity(len as usize); self.read_to_end(&mut content).map_err(::error::from)?; - let encoding_name = self.headers().get::<::header::ContentType>() - .and_then(|content_type| { - content_type.get_param("charset") + let content_type = self.headers().get(::header::CONTENT_TYPE) + .and_then(|value| { + value.to_str().ok() + }) + .and_then(|value| { + value.parse::().ok() + }); + let encoding_name = content_type + .as_ref() + .and_then(|mime| { + mime + .get_param("charset") .map(|charset| charset.as_str()) }) .unwrap_or("utf-8"); @@ -252,7 +262,7 @@ impl Response { /// let res = reqwest::get("http://httpbin.org/status/400")? /// .error_for_status(); /// if let Err(err) = res { - /// assert_eq!(err.status(), Some(reqwest::StatusCode::BadRequest)); + /// assert_eq!(err.status(), Some(reqwest::StatusCode::BAD_REQUEST)); /// } /// # Ok(()) /// # } @@ -260,12 +270,13 @@ impl Response { /// ``` #[inline] pub fn error_for_status(self) -> ::Result { - let Response { body, inner, _thread_handle } = self; + let Response { body, content_length, inner, _thread_handle } = self; inner.error_for_status().map(move |inner| { Response { - inner: inner, - body: body, - _thread_handle: _thread_handle, + inner, + body, + content_length, + _thread_handle, } }) } @@ -306,6 +317,7 @@ impl Stream for WaitBody { pub fn new(mut res: async_impl::Response, timeout: Option, thread: KeepCoreThreadAlive) -> Response { let body = mem::replace(res.body_mut(), async_impl::Decoder::empty()); + let len = body.content_length(); let body = async_impl::ReadableChunks::new(WaitBody { inner: wait::stream(body, timeout) }); @@ -313,6 +325,7 @@ pub fn new(mut res: async_impl::Response, timeout: Option, thread: Kee Response { inner: res, body: body, + content_length: len, _thread_handle: thread, } } diff --git a/src/wait.rs b/src/wait.rs index 0890967..6360088 100644 --- a/src/wait.rs +++ b/src/wait.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use std::thread; use std::time::{Duration, Instant}; -use futures::{Async, AsyncSink, Future, Sink, Stream}; +use futures::{Async, Future, Stream}; use futures::executor::{self, Notify}; // pub(crate) @@ -43,14 +43,6 @@ where S: Stream { } } -pub fn sink(sink: S, timeout: Option) -> WaitSink -where S: Sink { - WaitSink { - sink: executor::spawn(sink), - timeout: timeout, - } -} - #[derive(Debug)] pub enum Waited { TimedOut, @@ -113,49 +105,6 @@ where S: Stream { } } -pub struct WaitSink { - sink: executor::Spawn, - timeout: Option, -} - -impl WaitSink -where S: Sink { - pub fn send(&mut self, mut item: S::SinkItem) -> Result<(), Waited> { - if let Some(dur) = self.timeout { - - let start = Instant::now(); - let deadline = start + dur; - let notify = Arc::new(ThreadNotify { - thread: thread::current(), - }); - - loop { - let now = Instant::now(); - if now >= deadline { - return Err(Waited::TimedOut); - } - item = match self.sink.start_send_notify(item, ¬ify, 0)? { - AsyncSink::Ready => return Ok(()), - AsyncSink::NotReady(val) => val, - }; - thread::park_timeout(deadline - now); - } - } else { - let notify = Arc::new(ThreadNotify { - thread: thread::current(), - }); - - loop { - item = match self.sink.start_send_notify(item, ¬ify, 0)? { - AsyncSink::Ready => return Ok(()), - AsyncSink::NotReady(val) => val, - }; - thread::park(); - } - } - } -} - struct ThreadNotify { thread: thread::Thread, } diff --git a/tests/async.rs b/tests/async.rs index 937c322..c7aea0d 100644 --- a/tests/async.rs +++ b/tests/async.rs @@ -1,16 +1,15 @@ #![cfg(feature="unstable")] extern crate futures; -extern crate tokio_core; -extern crate reqwest; extern crate libflate; +extern crate reqwest; +extern crate tokio; #[macro_use] mod support; use reqwest::unstable::async::Client; use futures::{Future, Stream}; -use tokio_core::reactor::Core; use std::io::Write; use std::time::Duration; @@ -46,10 +45,10 @@ fn test_gzip(response_size: usize, chunk_size: usize) { let server = server! { request: b"\ GET /gzip HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", chunk_size: chunk_size, @@ -57,9 +56,9 @@ fn test_gzip(response_size: usize, chunk_size: usize) { response: response }; - let mut core = Core::new().unwrap(); + let mut rt = tokio::runtime::current_thread::Runtime::new().expect("new rt"); - let client = Client::new(&core.handle()); + let client = Client::new(); let res_future = client.get(&format!("http://{}/gzip", server.addr())) .send() @@ -75,5 +74,5 @@ fn test_gzip(response_size: usize, chunk_size: usize) { Ok(()) }); - core.run(res_future).unwrap(); + rt.block_on(res_future).unwrap(); } diff --git a/tests/client.rs b/tests/client.rs index 099d3c7..7a52cd9 100644 --- a/tests/client.rs +++ b/tests/client.rs @@ -10,10 +10,10 @@ fn test_response_text() { let server = server! { request: b"\ GET /text HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -28,11 +28,9 @@ fn test_response_text() { let url = format!("http://{}/text", server.addr()); let mut res = reqwest::get(&url).unwrap(); assert_eq!(res.url().as_str(), &url); - assert_eq!(res.status(), reqwest::StatusCode::Ok); - assert_eq!(res.headers().get(), - Some(&reqwest::header::Server::new("test".to_string()))); - assert_eq!(res.headers().get(), - Some(&reqwest::header::ContentLength(5))); + assert_eq!(res.status(), reqwest::StatusCode::OK); + assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test"); + assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"5"); let body = res.text().unwrap(); assert_eq!(b"Hello", body.as_bytes()); @@ -43,10 +41,10 @@ fn test_response_non_utf_8_text() { let server = server! { request: b"\ GET /text HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -62,11 +60,9 @@ fn test_response_non_utf_8_text() { let url = format!("http://{}/text", server.addr()); let mut res = reqwest::get(&url).unwrap(); assert_eq!(res.url().as_str(), &url); - assert_eq!(res.status(), reqwest::StatusCode::Ok); - assert_eq!(res.headers().get(), - Some(&reqwest::header::Server::new("test".to_string()))); - assert_eq!(res.headers().get(), - Some(&reqwest::header::ContentLength(4))); + assert_eq!(res.status(), reqwest::StatusCode::OK); + assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test"); + assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"4"); let body = res.text().unwrap(); assert_eq!("你好", &body); @@ -78,10 +74,10 @@ fn test_response_copy_to() { let server = server! { request: b"\ GET /1 HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -96,11 +92,9 @@ fn test_response_copy_to() { let url = format!("http://{}/1", server.addr()); let mut res = reqwest::get(&url).unwrap(); assert_eq!(res.url().as_str(), &url); - assert_eq!(res.status(), reqwest::StatusCode::Ok); - assert_eq!(res.headers().get(), - Some(&reqwest::header::Server::new("test".to_string()))); - assert_eq!(res.headers().get(), - Some(&reqwest::header::ContentLength(5))); + assert_eq!(res.status(), reqwest::StatusCode::OK); + assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test"); + assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"5"); let mut buf: Vec = vec![]; res.copy_to(&mut buf).unwrap(); @@ -112,10 +106,10 @@ fn test_get() { let server = server! { request: b"\ GET /1 HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -130,11 +124,9 @@ fn test_get() { let mut res = reqwest::get(&url).unwrap(); assert_eq!(res.url().as_str(), &url); - assert_eq!(res.status(), reqwest::StatusCode::Ok); - assert_eq!(res.headers().get(), - Some(&reqwest::header::Server::new("test".to_string()))); - assert_eq!(res.headers().get(), - Some(&reqwest::header::ContentLength(0))); + assert_eq!(res.status(), reqwest::StatusCode::OK); + assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test"); + assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"0"); let mut buf = [0; 1024]; let n = res.read(&mut buf).unwrap(); @@ -146,11 +138,11 @@ fn test_post() { let server = server! { request: b"\ POST /2 HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Content-Length: 5\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + content-length: 5\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ Hello\ ", @@ -170,11 +162,9 @@ fn test_post() { .unwrap(); assert_eq!(res.url().as_str(), &url); - assert_eq!(res.status(), reqwest::StatusCode::Ok); - assert_eq!(res.headers().get(), - Some(&reqwest::header::Server::new("post"))); - assert_eq!(res.headers().get(), - Some(&reqwest::header::ContentLength(0))); + assert_eq!(res.status(), reqwest::StatusCode::OK); + assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"post"); + assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"0"); let mut buf = [0; 1024]; let n = res.read(&mut buf).unwrap(); @@ -188,10 +178,10 @@ fn test_error_for_status_4xx() { let server = server! { request: b"\ GET /1 HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -207,7 +197,7 @@ fn test_error_for_status_4xx() { let err = res.error_for_status().err().unwrap(); assert!(err.is_client_error()); - assert_eq!(err.status(), Some(reqwest::StatusCode::BadRequest)); + assert_eq!(err.status(), Some(reqwest::StatusCode::BAD_REQUEST)); } /// Calling `Response::error_for_status`` on a response with status in 5xx @@ -217,10 +207,10 @@ fn test_error_for_status_5xx() { let server = server! { request: b"\ GET /1 HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -236,17 +226,14 @@ fn test_error_for_status_5xx() { let err = res.error_for_status().err().unwrap(); assert!(err.is_server_error()); - assert_eq!(err.status(), Some(reqwest::StatusCode::InternalServerError)); + assert_eq!(err.status(), Some(reqwest::StatusCode::INTERNAL_SERVER_ERROR)); } #[test] fn test_default_headers() { use reqwest::header; - let mut headers = header::Headers::with_capacity(1); - let mut cookies = header::Cookie::new(); - cookies.set("a", "b"); - cookies.set("c", "d"); - headers.set(cookies); + let mut headers = header::HeaderMap::with_capacity(1); + headers.insert(header::COOKIE, header::HeaderValue::from_static("a=b;c=d")); let client = reqwest::Client::builder() .default_headers(headers) .build().unwrap(); @@ -254,11 +241,11 @@ fn test_default_headers() { let server = server! { request: b"\ GET /1 HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Cookie: a=b; c=d\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + cookie: a=b;c=d\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -273,20 +260,18 @@ fn test_default_headers() { let res = client.get(&url).send().unwrap(); assert_eq!(res.url().as_str(), &url); - assert_eq!(res.status(), reqwest::StatusCode::Ok); - assert_eq!(res.headers().get(), - Some(&reqwest::header::Server::new("test"))); - assert_eq!(res.headers().get(), - Some(&reqwest::header::ContentLength(0))); + assert_eq!(res.status(), reqwest::StatusCode::OK); + assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test"); + assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"0"); let server = server! { request: b"\ GET /2 HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Cookie: a=b; c=d\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + cookie: a=b;c=d\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -301,18 +286,16 @@ fn test_default_headers() { let res = client.get(&url).send().unwrap(); assert_eq!(res.url().as_str(), &url); - assert_eq!(res.status(), reqwest::StatusCode::Ok); - assert_eq!(res.headers().get(), - Some(&reqwest::header::Server::new("test"))); - assert_eq!(res.headers().get(), - Some(&reqwest::header::ContentLength(0))); + assert_eq!(res.status(), reqwest::StatusCode::OK); + assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test"); + assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"0"); } #[test] fn test_override_default_headers() { use reqwest::header; - let mut headers = header::Headers::with_capacity(1); - headers.set(header::Authorization("iamatoken".to_string())); + let mut headers = header::HeaderMap::with_capacity(1); + headers.insert(header::AUTHORIZATION, header::HeaderValue::from_static("iamatoken")); let client = reqwest::Client::builder() .default_headers(headers) .build().unwrap(); @@ -320,11 +303,11 @@ fn test_override_default_headers() { let server = server! { request: b"\ GET /3 HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Authorization: secret\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + authorization: secret\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -336,13 +319,11 @@ fn test_override_default_headers() { }; let url = format!("http://{}/3", server.addr()); - let res = client.get(&url).header(header::Authorization("secret".to_string())).send().unwrap(); + let res = client.get(&url).header(header::AUTHORIZATION, header::HeaderValue::from_static("secret")).send().unwrap(); assert_eq!(res.url().as_str(), &url); - assert_eq!(res.status(), reqwest::StatusCode::Ok); - assert_eq!(res.headers().get(), - Some(&reqwest::header::Server::new("test"))); - assert_eq!(res.headers().get(), - Some(&reqwest::header::ContentLength(0))); + assert_eq!(res.status(), reqwest::StatusCode::OK); + assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test"); + assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"0"); } diff --git a/tests/gzip.rs b/tests/gzip.rs index 02a3083..5ff34ff 100644 --- a/tests/gzip.rs +++ b/tests/gzip.rs @@ -31,10 +31,10 @@ fn test_gzip_response() { let server = server! { request: b"\ GET /gzip HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", chunk_size: chunk_size, @@ -54,10 +54,10 @@ fn test_gzip_empty_body() { let server = server! { request: b"\ HEAD /gzip HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -85,10 +85,10 @@ fn test_gzip_invalid_body() { let server = server! { request: b"\ GET /gzip HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -113,10 +113,10 @@ fn test_accept_header_is_not_changed_if_set() { let server = server! { request: b"\ GET /accept HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: application/json\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: application/json\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -130,11 +130,11 @@ fn test_accept_header_is_not_changed_if_set() { let res = client .get(&format!("http://{}/accept", server.addr())) - .header(reqwest::header::Accept::json()) + .header(reqwest::header::ACCEPT, reqwest::header::HeaderValue::from_static("application/json")) .send() .unwrap(); - assert_eq!(res.status(), reqwest::StatusCode::Ok); + assert_eq!(res.status(), reqwest::StatusCode::OK); } #[test] @@ -142,10 +142,10 @@ fn test_accept_encoding_header_is_not_changed_if_set() { let server = server! { request: b"\ GET /accept-encoding HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: identity\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: identity\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -158,11 +158,9 @@ fn test_accept_encoding_header_is_not_changed_if_set() { let client = reqwest::Client::new(); let res = client.get(&format!("http://{}/accept-encoding", server.addr())) - .header(reqwest::header::AcceptEncoding( - vec![reqwest::header::qitem(reqwest::header::Encoding::Identity)] - )) + .header(reqwest::header::ACCEPT_ENCODING, reqwest::header::HeaderValue::from_static("identity")) .send() .unwrap(); - assert_eq!(res.status(), reqwest::StatusCode::Ok); + assert_eq!(res.status(), reqwest::StatusCode::OK); } diff --git a/tests/multipart.rs b/tests/multipart.rs index 8399249..d9b6a41 100644 --- a/tests/multipart.rs +++ b/tests/multipart.rs @@ -21,12 +21,12 @@ fn test_multipart() { let server = server! { request: format!("\ POST /multipart/1 HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Content-Type: multipart/form-data; boundary={}\r\n\ - Content-Length: 123\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + content-type: multipart/form-data; boundary={}\r\n\ + content-length: 123\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ {}\ ", form.boundary(), expected_body), @@ -47,5 +47,5 @@ fn test_multipart() { .unwrap(); assert_eq!(res.url().as_str(), &url); - assert_eq!(res.status(), reqwest::StatusCode::Ok); + assert_eq!(res.status(), reqwest::StatusCode::OK); } diff --git a/tests/proxy.rs b/tests/proxy.rs index 75dbbb6..c805749 100644 --- a/tests/proxy.rs +++ b/tests/proxy.rs @@ -8,10 +8,10 @@ fn test_http_proxy() { let server = server! { request: b"\ GET http://hyper.rs/prox HTTP/1.1\r\n\ - Host: hyper.rs\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: hyper.rs\r\n\ \r\n\ ", response: b"\ @@ -34,7 +34,6 @@ fn test_http_proxy() { .unwrap(); assert_eq!(res.url().as_str(), url); - assert_eq!(res.status(), reqwest::StatusCode::Ok); - assert_eq!(res.headers().get(), - Some(&reqwest::header::Server::new("proxied"))); + assert_eq!(res.status(), reqwest::StatusCode::OK); + assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"proxied"); } diff --git a/tests/redirect.rs b/tests/redirect.rs index 577f3e4..01cdfba 100644 --- a/tests/redirect.rs +++ b/tests/redirect.rs @@ -12,10 +12,10 @@ fn test_redirect_301_and_302_and_303_changes_post_to_get() { let redirect = server! { request: format!("\ POST /{} HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", code), response: format!("\ @@ -29,11 +29,11 @@ fn test_redirect_301_and_302_and_303_changes_post_to_get() { request: format!("\ GET /dst HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ - Referer: http://$HOST/{}\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + referer: http://$HOST/{}\r\n\ + host: $HOST\r\n\ \r\n\ ", code), response: b"\ @@ -50,9 +50,8 @@ fn test_redirect_301_and_302_and_303_changes_post_to_get() { .send() .unwrap(); assert_eq!(res.url().as_str(), dst); - assert_eq!(res.status(), reqwest::StatusCode::Ok); - assert_eq!(res.headers().get(), - Some(&reqwest::header::Server::new("test-dst".to_string()))); + assert_eq!(res.status(), reqwest::StatusCode::OK); + assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test-dst"); } } @@ -64,10 +63,10 @@ fn test_redirect_307_and_308_tries_to_get_again() { let redirect = server! { request: format!("\ GET /{} HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", code), response: format!("\ @@ -81,11 +80,11 @@ fn test_redirect_307_and_308_tries_to_get_again() { request: format!("\ GET /dst HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ - Referer: http://$HOST/{}\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + referer: http://$HOST/{}\r\n\ + host: $HOST\r\n\ \r\n\ ", code), response: b"\ @@ -102,9 +101,8 @@ fn test_redirect_307_and_308_tries_to_get_again() { .send() .unwrap(); assert_eq!(res.url().as_str(), dst); - assert_eq!(res.status(), reqwest::StatusCode::Ok); - assert_eq!(res.headers().get(), - Some(&reqwest::header::Server::new("test-dst".to_string()))); + assert_eq!(res.status(), reqwest::StatusCode::OK); + assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test-dst"); } } @@ -116,11 +114,11 @@ fn test_redirect_307_and_308_tries_to_post_again() { let redirect = server! { request: format!("\ POST /{} HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Content-Length: 5\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + content-length: 5\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ Hello\ ", code), @@ -135,12 +133,12 @@ fn test_redirect_307_and_308_tries_to_post_again() { request: format!("\ POST /dst HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Content-Length: 5\r\n\ - Accept-Encoding: gzip\r\n\ - Referer: http://$HOST/{}\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + content-length: 5\r\n\ + accept-encoding: gzip\r\n\ + referer: http://$HOST/{}\r\n\ + host: $HOST\r\n\ \r\n\ Hello\ ", code), @@ -159,9 +157,8 @@ fn test_redirect_307_and_308_tries_to_post_again() { .send() .unwrap(); assert_eq!(res.url().as_str(), dst); - assert_eq!(res.status(), reqwest::StatusCode::Ok); - assert_eq!(res.headers().get(), - Some(&reqwest::header::Server::new("test-dst".to_string()))); + assert_eq!(res.status(), reqwest::StatusCode::OK); + assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test-dst"); } } @@ -173,11 +170,11 @@ fn test_redirect_307_does_not_try_if_reader_cannot_reset() { let redirect = server! { request: format!("\ POST /{} HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ - Transfer-Encoding: chunked\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ + transfer-encoding: chunked\r\n\ \r\n\ 5\r\n\ Hello\r\n\ @@ -200,7 +197,7 @@ fn test_redirect_307_does_not_try_if_reader_cannot_reset() { .send() .unwrap(); assert_eq!(res.url().as_str(), url); - assert_eq!(res.status(), reqwest::StatusCode::try_from(code).unwrap()); + assert_eq!(res.status(), reqwest::StatusCode::from_u16(code).unwrap()); } } @@ -211,10 +208,10 @@ fn test_redirect_removes_sensitive_headers() { let end_server = server! { request: b"\ GET /otherhost HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -228,11 +225,11 @@ fn test_redirect_removes_sensitive_headers() { let mid_server = server! { request: b"\ GET /sensitive HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Cookie: foo=bar\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + cookie: foo=bar\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: format!("\ @@ -244,14 +241,12 @@ fn test_redirect_removes_sensitive_headers() { ", end_server.addr()) }; - let mut cookie = reqwest::header::Cookie::new(); - cookie.set("foo", "bar"); reqwest::Client::builder() .referer(false) .build() .unwrap() .get(&format!("http://{}/sensitive", mid_server.addr())) - .header(cookie) + .header(reqwest::header::COOKIE, reqwest::header::HeaderValue::from_static("foo=bar")) .send() .unwrap(); } @@ -261,10 +256,10 @@ fn test_redirect_policy_can_return_errors() { let server = server! { request: b"\ GET /loop HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -285,10 +280,10 @@ fn test_redirect_policy_can_stop_redirects_without_an_error() { let server = server! { request: b"\ GET /no-redirect HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -311,9 +306,8 @@ fn test_redirect_policy_can_stop_redirects_without_an_error() { .unwrap(); assert_eq!(res.url().as_str(), url); - assert_eq!(res.status(), reqwest::StatusCode::Found); - assert_eq!(res.headers().get(), - Some(&reqwest::header::Server::new("test-dont".to_string()))); + assert_eq!(res.status(), reqwest::StatusCode::FOUND); + assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test-dont"); } #[test] @@ -321,10 +315,10 @@ fn test_referer_is_not_set_if_disabled() { let server = server! { request: b"\ GET /no-refer HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -338,10 +332,10 @@ fn test_referer_is_not_set_if_disabled() { request: b"\ GET /dst HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ diff --git a/tests/timeouts.rs b/tests/timeouts.rs index 088f5f8..614e83f 100644 --- a/tests/timeouts.rs +++ b/tests/timeouts.rs @@ -11,11 +11,11 @@ fn test_write_timeout() { let server = server! { request: b"\ POST /write-timeout HTTP/1.1\r\n\ - Host: $HOST\r\n\ - Content-Length: 5\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + content-length: 5\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ Hello\ ", @@ -34,7 +34,7 @@ fn test_write_timeout() { .build() .unwrap() .post(&url) - .header(reqwest::header::ContentLength(5)) + .header(reqwest::header::CONTENT_LENGTH, reqwest::header::HeaderValue::from_static("5")) .body(reqwest::Body::new(&b"Hello"[..])) .send() .unwrap_err(); @@ -49,10 +49,10 @@ fn test_response_timeout() { let server = server! { request: b"\ GET /response-timeout HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -80,10 +80,10 @@ fn test_read_timeout() { let server = server! { request: b"\ GET /read-timeout HTTP/1.1\r\n\ - Host: $HOST\r\n\ - User-Agent: $USERAGENT\r\n\ - Accept: */*\r\n\ - Accept-Encoding: gzip\r\n\ + user-agent: $USERAGENT\r\n\ + accept: */*\r\n\ + accept-encoding: gzip\r\n\ + host: $HOST\r\n\ \r\n\ ", response: b"\ @@ -105,9 +105,8 @@ fn test_read_timeout() { .unwrap(); assert_eq!(res.url().as_str(), &url); - assert_eq!(res.status(), reqwest::StatusCode::Ok); - assert_eq!(res.headers().get(), - Some(&reqwest::header::ContentLength(5))); + assert_eq!(res.status(), reqwest::StatusCode::OK); + assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"5"); let mut buf = [0; 1024]; let err = res.read(&mut buf).unwrap_err();