Upgrade hyper to 0.12

Closes #304
This commit is contained in:
Yash Srivastav
2018-07-05 13:03:31 -04:00
committed by Sean McArthur
parent 7bd3619ece
commit c417d6dab8
27 changed files with 634 additions and 650 deletions

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "reqwest" 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" description = "higher level HTTP client library"
keywords = ["http", "request", "client"] keywords = ["http", "request", "client"]
repository = "https://github.com/seanmonstar/reqwest" repository = "https://github.com/seanmonstar/reqwest"
@@ -9,20 +9,26 @@ authors = ["Sean McArthur <sean@seanmonstar.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
categories = ["web-programming::http-client"] categories = ["web-programming::http-client"]
publish = false # pre
[dependencies] [dependencies]
base64 = "~0.6.0"
bytes = "0.4" bytes = "0.4"
encoding_rs = "0.7" encoding_rs = "0.7"
futures = "0.1.15" futures = "0.1.21"
hyper = "0.11.22" http = "0.1.5"
hyper-tls = "0.1.2" hyper = "0.12.2"
hyper-tls = "0.2.1"
libflate = "0.1.11" libflate = "0.1.11"
log = "0.4" 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" native-tls = "0.1.5"
serde = "1.0" serde = "1.0"
serde_json = "1.0" serde_json = "1.0"
serde_urlencoded = "0.5" serde_urlencoded = "0.5"
tokio-core = "0.1.6" tokio-core = "0.1.17"
tokio = "0.1.7"
tokio-io = "0.1" tokio-io = "0.1"
tokio-tls = "0.1" tokio-tls = "0.1"
url = "1.2" url = "1.2"

View File

@@ -20,7 +20,7 @@ error_chain! {
fn run() -> Result<()> { fn run() -> Result<()> {
let mut core = tokio_core::reactor::Core::new()?; 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") let work = client.get("https://hyper.rs")
.send() .send()

View File

@@ -22,7 +22,7 @@ fn run() -> Result<()> {
let mut res = reqwest::get("https://www.rust-lang.org/en-US/")?; let mut res = reqwest::get("https://www.rust-lang.org/en-US/")?;
println!("Status: {}", res.status()); println!("Status: {}", res.status());
println!("Headers:\n{}", res.headers()); println!("Headers:\n{:?}", res.headers());
// copy the response body directly to stdout // copy the response body directly to stdout
let _ = std::io::copy(&mut res, &mut std::io::stdout())?; let _ = std::io::copy(&mut res, &mut std::io::stdout())?;

View File

@@ -2,6 +2,7 @@ use std::fmt;
use futures::{Stream, Poll, Async}; use futures::{Stream, Poll, Async};
use bytes::Bytes; use bytes::Bytes;
use hyper::body::Payload;
/// An asynchronous `Stream`. /// An asynchronous `Stream`.
pub struct Body { pub struct Body {
@@ -20,6 +21,13 @@ impl Body {
Inner::Reusable(_) => unreachable!(), Inner::Reusable(_) => unreachable!(),
} }
} }
pub(crate) fn content_length(&self) -> Option<u64> {
match self.inner {
Inner::Reusable(ref bytes) => Some(bytes.len() as u64),
Inner::Hyper(ref body) => body.content_length(),
}
}
} }
impl Stream for Body { impl Stream for Body {

View File

@@ -4,11 +4,11 @@ use std::time::Duration;
use bytes::Bytes; use bytes::Bytes;
use futures::{Async, Future, Poll}; use futures::{Async, Future, Poll};
use hyper::client::FutureResponse; use hyper::client::ResponseFuture;
use hyper::header::{Headers, Location, Referer, UserAgent, Accept, Encoding, use header::{HeaderMap, HeaderValue, LOCATION, USER_AGENT, REFERER, ACCEPT,
AcceptEncoding, Range, qitem}; ACCEPT_ENCODING, RANGE};
use mime::{self};
use native_tls::{TlsConnector, TlsConnectorBuilder}; use native_tls::{TlsConnector, TlsConnectorBuilder};
use tokio_core::reactor::Handle;
use super::body; use super::body;
@@ -63,7 +63,7 @@ pub struct ClientBuilder {
struct Config { struct Config {
gzip: bool, gzip: bool,
headers: Headers, headers: HeaderMap,
hostname_verification: bool, hostname_verification: bool,
proxies: Vec<Proxy>, proxies: Vec<Proxy>,
redirect_policy: RedirectPolicy, redirect_policy: RedirectPolicy,
@@ -78,9 +78,9 @@ impl ClientBuilder {
pub fn new() -> ClientBuilder { pub fn new() -> ClientBuilder {
match TlsConnector::builder() { match TlsConnector::builder() {
Ok(tls_connector_builder) => { Ok(tls_connector_builder) => {
let mut headers = Headers::with_capacity(2); let mut headers: HeaderMap<HeaderValue> = HeaderMap::with_capacity(2);
headers.set(UserAgent::new(DEFAULT_USER_AGENT)); headers.insert(USER_AGENT, HeaderValue::from_static(DEFAULT_USER_AGENT));
headers.set(Accept::star()); headers.insert(ACCEPT, HeaderValue::from_str(mime::STAR_STAR.as_ref()).expect("unable to parse mime"));
ClientBuilder { ClientBuilder {
config: Some(Config { config: Some(Config {
@@ -114,7 +114,7 @@ impl ClientBuilder {
/// ///
/// This method consumes the internal state of the builder. /// This method consumes the internal state of the builder.
/// Trying to use this builder again after calling `build` will panic. /// Trying to use this builder again after calling `build` will panic.
pub fn build(&mut self, handle: &Handle) -> ::Result<Client> { pub fn build(&mut self) -> ::Result<Client> {
if let Some(err) = self.err.take() { if let Some(err) = self.err.take() {
return Err(err); return Err(err);
} }
@@ -126,14 +126,13 @@ impl ClientBuilder {
let proxies = Arc::new(config.proxies); 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 { if !config.hostname_verification {
connector.danger_disable_hostname_verification(); connector.danger_disable_hostname_verification();
} }
let hyper_client = ::hyper::Client::configure() let hyper_client = ::hyper::Client::builder()
.connector(connector) .build(connector);
.build(handle);
Ok(Client { Ok(Client {
inner: Arc::new(ClientRef { inner: Arc::new(ClientRef {
@@ -200,9 +199,11 @@ impl ClientBuilder {
/// Sets the default headers for every request. /// Sets the default headers for every request.
#[inline] #[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) { 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 self
} }
@@ -287,9 +288,9 @@ impl Client {
/// initialized. Use `Client::builder()` if you wish to handle the failure /// initialized. Use `Client::builder()` if you wish to handle the failure
/// as an `Error` instead of panicking. /// as an `Error` instead of panicking.
#[inline] #[inline]
pub fn new(handle: &Handle) -> Client { pub fn new() -> Client {
ClientBuilder::new() ClientBuilder::new()
.build(handle) .build()
.expect("TLS failed to initialize") .expect("TLS failed to initialize")
} }
@@ -305,7 +306,7 @@ impl Client {
/// ///
/// This method fails whenever supplied `Url` cannot be parsed. /// This method fails whenever supplied `Url` cannot be parsed.
pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder { pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder {
self.request(Method::Get, url) self.request(Method::GET, url)
} }
/// Convenience method to make a `POST` request to a 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. /// This method fails whenever supplied `Url` cannot be parsed.
pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder { pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder {
self.request(Method::Post, url) self.request(Method::POST, url)
} }
/// Convenience method to make a `PUT` request to a 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. /// This method fails whenever supplied `Url` cannot be parsed.
pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder { pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder {
self.request(Method::Put, url) self.request(Method::PUT, url)
} }
/// Convenience method to make a `PATCH` request to a 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. /// This method fails whenever supplied `Url` cannot be parsed.
pub fn patch<U: IntoUrl>(&self, url: U) -> RequestBuilder { pub fn patch<U: IntoUrl>(&self, url: U) -> RequestBuilder {
self.request(Method::Patch, url) self.request(Method::PATCH, url)
} }
/// Convenience method to make a `DELETE` request to a 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. /// This method fails whenever supplied `Url` cannot be parsed.
pub fn delete<U: IntoUrl>(&self, url: U) -> RequestBuilder { pub fn delete<U: IntoUrl>(&self, url: U) -> RequestBuilder {
self.request(Method::Delete, url) self.request(Method::DELETE, url)
} }
/// Convenience method to make a `HEAD` request to a 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. /// This method fails whenever supplied `Url` cannot be parsed.
pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder { pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder {
self.request(Method::Head, url) self.request(Method::HEAD, url)
} }
/// Start building a `Request` with the `Method` and `Url`. /// Start building a `Request` with the `Method` and `Url`.
@@ -395,28 +396,35 @@ impl Client {
) = request::pieces(req); ) = request::pieces(req);
let mut headers = self.inner.headers.clone(); // default headers 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 && if self.inner.gzip &&
!headers.has::<AcceptEncoding>() && !headers.contains_key(ACCEPT_ENCODING) &&
!headers.has::<Range>() { !headers.contains_key(RANGE) {
headers.set(AcceptEncoding(vec![qitem(Encoding::Gzip)])); headers.insert(ACCEPT_ENCODING, HeaderValue::from_static("gzip"));
} }
let uri = to_uri(&url); 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) { let (reusable, body) = match body {
if uri.scheme() == Some("http") { Some(body) => {
req.set_proxy(true); 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); let in_flight = self.inner.hyper.request(req);
@@ -425,7 +433,7 @@ impl Client {
method: method, method: method,
url: url, url: url,
headers: headers, headers: headers,
body: body, body: reusable,
urls: Vec::new(), urls: Vec::new(),
@@ -456,7 +464,7 @@ impl fmt::Debug for ClientBuilder {
struct ClientRef { struct ClientRef {
gzip: bool, gzip: bool,
headers: Headers, headers: HeaderMap,
hyper: HyperClient, hyper: HyperClient,
proxies: Arc<Vec<Proxy>>, proxies: Arc<Vec<Proxy>>,
redirect_policy: RedirectPolicy, redirect_policy: RedirectPolicy,
@@ -475,14 +483,14 @@ enum PendingInner {
pub struct PendingRequest { pub struct PendingRequest {
method: Method, method: Method,
url: Url, url: Url,
headers: Headers, headers: HeaderMap,
body: Option<Option<Bytes>>, body: Option<Option<Bytes>>,
urls: Vec<Url>, urls: Vec<Url>,
client: Arc<ClientRef>, client: Arc<ClientRef>,
in_flight: FutureResponse, in_flight: ResponseFuture,
} }
@@ -509,20 +517,20 @@ impl Future for PendingRequest {
Async::NotReady => return Ok(Async::NotReady), Async::NotReady => return Ok(Async::NotReady),
}; };
let should_redirect = match res.status() { let should_redirect = match res.status() {
StatusCode::MovedPermanently | StatusCode::MOVED_PERMANENTLY |
StatusCode::Found | StatusCode::FOUND |
StatusCode::SeeOther => { StatusCode::SEE_OTHER => {
self.body = None; self.body = None;
match self.method { match self.method {
Method::Get | Method::Head => {}, Method::GET | Method::HEAD => {},
_ => { _ => {
self.method = Method::Get; self.method = Method::GET;
} }
} }
true true
}, },
StatusCode::TemporaryRedirect | StatusCode::TEMPORARY_REDIRECT |
StatusCode::PermanentRedirect => match self.body { StatusCode::PERMANENT_REDIRECT => match self.body {
Some(Some(_)) | None => true, Some(Some(_)) | None => true,
Some(None) => false, Some(None) => false,
}, },
@@ -530,12 +538,12 @@ impl Future for PendingRequest {
}; };
if should_redirect { if should_redirect {
let loc = res.headers() let loc = res.headers()
.get::<Location>() .get(LOCATION)
.map(|loc| self.url.join(loc)); .map(|loc| self.url.join(loc.to_str().expect("")));
if let Some(Ok(loc)) = loc { if let Some(Ok(loc)) = loc {
if self.client.referer { if self.client.referer {
if let Some(referer) = make_referer(&loc, &self.url) { if let Some(referer) = make_referer(&loc, &self.url) {
self.headers.set(referer); self.headers.insert(REFERER, referer);
} }
} }
self.urls.push(self.url.clone()); self.urls.push(self.url.clone());
@@ -553,19 +561,17 @@ impl Future for PendingRequest {
remove_sensitive_headers(&mut self.headers, &self.url, &self.urls); remove_sensitive_headers(&mut self.headers, &self.url, &self.urls);
debug!("redirecting to {:?} '{}'", self.method, self.url); debug!("redirecting to {:?} '{}'", self.method, self.url);
let uri = to_uri(&self.url); let uri = to_uri(&self.url);
let mut req = ::hyper::Request::new( let body = match self.body {
self.method.clone(), Some(Some(ref body)) => ::hyper::Body::from(body.clone()),
uri.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(); *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); self.in_flight = self.client.hyper.request(req);
continue; continue;
}, },
@@ -607,7 +613,7 @@ impl fmt::Debug for Pending {
} }
} }
fn make_referer(next: &Url, previous: &Url) -> Option<Referer> { fn make_referer(next: &Url, previous: &Url) -> Option<HeaderValue> {
if next.scheme() == "http" && previous.scheme() == "https" { if next.scheme() == "http" && previous.scheme() == "https" {
return None; return None;
} }
@@ -616,7 +622,7 @@ fn make_referer(next: &Url, previous: &Url) -> Option<Referer> {
let _ = referer.set_username(""); let _ = referer.set_username("");
let _ = referer.set_password(None); let _ = referer.set_password(None);
referer.set_fragment(None); referer.set_fragment(None);
Some(Referer::new(referer.into_string())) referer.as_str().parse().ok()
} }
// pub(crate) // pub(crate)

View File

@@ -33,12 +33,12 @@ use tokio_io::AsyncRead;
use tokio_io::io as async_io; use tokio_io::io as async_io;
use futures::{Async, Future, Poll, Stream}; use futures::{Async, Future, Poll, Stream};
use futures::stream::Concat2; 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::de::DeserializeOwned;
use serde_json; use serde_json;
use url::Url; use url::Url;
use header::{Headers, ContentEncoding, ContentLength, Encoding, TransferEncoding};
use super::{body, Body, Chunk}; use super::{body, Body, Chunk};
use error; use error;
@@ -111,6 +111,13 @@ impl Decoder {
inner: Inner::Pending(Pending::Gzip(ReadableChunks::new(body))) inner: Inner::Pending(Pending::Gzip(ReadableChunks::new(body)))
} }
} }
pub(crate) fn content_length(&self) -> Option<u64> {
match self.inner {
Inner::PlainText(ref body) => body.content_length(),
_ => None,
}
}
} }
impl Stream for Decoder { impl Stream for Decoder {
@@ -407,31 +414,33 @@ impl<S> ReadableChunks<S>
/// how to decode the content body of the request. /// how to decode the content body of the request.
/// ///
/// Uses the correct variant by inspecting the Content-Encoding header. /// 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 { if !check_gzip {
return Decoder::plain_text(body); return Decoder::plain_text(body);
} }
let content_encoding_gzip: bool; let content_encoding_gzip: bool;
let mut is_gzip = { let mut is_gzip = {
content_encoding_gzip = headers content_encoding_gzip = headers
.get::<ContentEncoding>() .get_all(CONTENT_ENCODING)
.map_or(false, |encs| encs.contains(&Encoding::Gzip)); .iter()
.fold(false, |acc, enc| acc || enc == HeaderValue::from_static("gzip"));
content_encoding_gzip || content_encoding_gzip ||
headers headers
.get::<TransferEncoding>() .get_all(TRANSFER_ENCODING)
.map_or(false, |encs| encs.contains(&Encoding::Gzip)) .iter()
.fold(false, |acc, enc| acc || enc == HeaderValue::from_static("gzip"))
}; };
if is_gzip { if is_gzip {
if let Some(content_length) = headers.get::<ContentLength>() { if let Some(content_length) = headers.get(CONTENT_LENGTH) {
if content_length.0 == 0 { if content_length == "0" {
warn!("GZipped response with content-length of 0"); warn!("GZipped response with content-length of 0");
is_gzip = false; is_gzip = false;
} }
} }
} }
if content_encoding_gzip { if content_encoding_gzip {
headers.remove::<ContentEncoding>(); headers.remove(CONTENT_ENCODING);
headers.remove::<ContentLength>(); headers.remove(CONTENT_LENGTH);
} }
if is_gzip { if is_gzip {
Decoder::gzip(body) Decoder::gzip(body)

View File

@@ -1,19 +1,22 @@
use std::fmt; use std::fmt;
use base64::{encode};
use mime::{self};
use serde::Serialize; use serde::Serialize;
use serde_json; use serde_json;
use serde_urlencoded; use serde_urlencoded;
use super::body::{self, Body}; use super::body::{self, Body};
use super::client::{Client, Pending, pending_err}; use super::client::{Client, Pending, pending_err};
use header::{ContentType, Headers}; use header::{CONTENT_TYPE, HeaderMap, HeaderName, HeaderValue};
use http::HttpTryFrom;
use {Method, Url}; use {Method, Url};
/// A request which can be executed with `Client::execute()`. /// A request which can be executed with `Client::execute()`.
pub struct Request { pub struct Request {
method: Method, method: Method,
url: Url, url: Url,
headers: Headers, headers: HeaderMap,
body: Option<Body>, body: Option<Body>,
} }
@@ -31,7 +34,7 @@ impl Request {
Request { Request {
method, method,
url, url,
headers: Headers::new(), headers: HeaderMap::new(),
body: None, body: None,
} }
} }
@@ -62,13 +65,13 @@ impl Request {
/// Get the headers. /// Get the headers.
#[inline] #[inline]
pub fn headers(&self) -> &Headers { pub fn headers(&self) -> &HeaderMap {
&self.headers &self.headers
} }
/// Get a mutable reference to the headers. /// Get a mutable reference to the headers.
#[inline] #[inline]
pub fn headers_mut(&mut self) -> &mut Headers { pub fn headers_mut(&mut self) -> &mut HeaderMap {
&mut self.headers &mut self.headers
} }
@@ -87,21 +90,32 @@ impl Request {
impl RequestBuilder { impl RequestBuilder {
/// Add a `Header` to this Request. /// Add a `Header` to this Request.
pub fn header<H>(&mut self, header: H) -> &mut RequestBuilder pub fn header<K, V>(&mut self, key: K, value: V) -> &mut RequestBuilder
where where
H: ::header::Header, HeaderName: HttpTryFrom<K>,
HeaderValue: HttpTryFrom<V>,
{ {
if let Some(req) = request_mut(&mut self.request, &self.err) { if let Some(req) = request_mut(&mut self.request, &self.err) {
req.headers_mut().set(header); match <HeaderName as HttpTryFrom<K>>::try_from(key) {
Ok(key) => {
match <HeaderValue as HttpTryFrom<V>>::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 self
} }
/// Add a set of Headers to the existing ones on this Request. /// Add a set of Headers to the existing ones on this Request.
/// ///
/// The headers will be merged in to any already set. /// 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) { 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 self
} }
@@ -112,10 +126,10 @@ impl RequestBuilder {
U: Into<String>, U: Into<String>,
P: Into<String>, P: Into<String>,
{ {
self.header(::header::Authorization(::header::Basic { let username = username.into();
username: username.into(), let password = password.map(|p| p.into()).unwrap_or(String::new());
password: password.map(|p| p.into()), let header_value = format!("basic {}:{}", username, encode(&password));
})) self.header(::header::AUTHORIZATION, HeaderValue::from_str(header_value.as_str()).expect(""))
} }
/// Set the request body. /// Set the request body.
@@ -162,7 +176,7 @@ impl RequestBuilder {
if let Some(req) = request_mut(&mut self.request, &self.err) { if let Some(req) = request_mut(&mut self.request, &self.err) {
match serde_urlencoded::to_string(form) { match serde_urlencoded::to_string(form) {
Ok(body) => { 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()); *req.body_mut() = Some(body.into());
}, },
Err(err) => self.err = Some(::error::from(err)), 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) { if let Some(req) = request_mut(&mut self.request, &self.err) {
match serde_json::to_vec(json) { match serde_json::to_vec(json) {
Ok(body) => { 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()); *req.body_mut() = Some(body.into());
}, },
Err(err) => self.err = Some(::error::from(err)), Err(err) => self.err = Some(::error::from(err)),
@@ -274,7 +288,7 @@ pub fn builder(client: Client, req: ::Result<Request>) -> RequestBuilder {
} }
#[inline] #[inline]
pub fn pieces(req: Request) -> (Method, Url, Headers, Option<Body>) { pub fn pieces(req: Request) -> (Method, Url, HeaderMap, Option<Body>) {
(req.method, req.url, req.headers, req.body) (req.method, req.url, req.headers, req.body)
} }
@@ -282,12 +296,10 @@ pub fn pieces(req: Request) -> (Method, Url, Headers, Option<Body>) {
mod tests { mod tests {
use super::Client; use super::Client;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use tokio_core::reactor::Core;
#[test] #[test]
fn add_query_append() { fn add_query_append() {
let mut core = Core::new().unwrap(); let client = Client::new();
let client = Client::new(&core.handle());
let some_url = "https://google.com/"; let some_url = "https://google.com/";
let mut r = client.get(some_url); let mut r = client.get(some_url);
@@ -300,8 +312,7 @@ mod tests {
#[test] #[test]
fn add_query_append_same() { fn add_query_append_same() {
let mut core = Core::new().unwrap(); let client = Client::new();
let client = Client::new(&core.handle());
let some_url = "https://google.com/"; let some_url = "https://google.com/";
let mut r = client.get(some_url); let mut r = client.get(some_url);
@@ -319,8 +330,7 @@ mod tests {
qux: i32, qux: i32,
} }
let mut core = Core::new().unwrap(); let client = Client::new();
let client = Client::new(&core.handle());
let some_url = "https://google.com/"; let some_url = "https://google.com/";
let mut r = client.get(some_url); let mut r = client.get(some_url);
@@ -338,8 +348,7 @@ mod tests {
params.insert("foo", "bar"); params.insert("foo", "bar");
params.insert("qux", "three"); params.insert("qux", "three");
let mut core = Core::new().unwrap(); let client = Client::new();
let client = Client::new(&core.handle());
let some_url = "https://google.com/"; let some_url = "https://google.com/";
let mut r = client.get(some_url); let mut r = client.get(some_url);

View File

@@ -13,7 +13,7 @@ use serde::de::DeserializeOwned;
use serde_json; use serde_json;
use url::Url; 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 super::{decoder, body, Body, Chunk, Decoder};
use error; use error;
@@ -21,7 +21,7 @@ use error;
/// A Response to a submitted `Request`. /// A Response to a submitted `Request`.
pub struct Response { pub struct Response {
status: StatusCode, status: StatusCode,
headers: Headers, headers: HeaderMap,
url: Url, url: Url,
body: Decoder, body: Decoder,
} }
@@ -41,13 +41,13 @@ impl Response {
/// Get the `Headers` of this `Response`. /// Get the `Headers` of this `Response`.
#[inline] #[inline]
pub fn headers(&self) -> &Headers { pub fn headers(&self) -> &HeaderMap {
&self.headers &self.headers
} }
/// Get a mutable reference to the `Headers` of this `Response`. /// Get a mutable reference to the `Headers` of this `Response`.
#[inline] #[inline]
pub fn headers_mut(&mut self) -> &mut Headers { pub fn headers_mut(&mut self) -> &mut HeaderMap {
&mut self.headers &mut self.headers
} }
@@ -99,7 +99,7 @@ impl Response {
/// // it could be any status between 400...599 /// // it could be any status between 400...599
/// assert_eq!( /// assert_eq!(
/// err.status(), /// err.status(),
/// Some(reqwest::StatusCode::BadRequest) /// Some(reqwest::StatusCode::BAD_REQUEST)
/// ); /// );
/// } /// }
/// } /// }
@@ -152,10 +152,10 @@ impl<T> fmt::Debug for Json<T> {
// pub(crate) // 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 status = res.status();
let mut headers = mem::replace(res.headers_mut(), Headers::new()); let mut headers = mem::replace(res.headers_mut(), HeaderMap::new());
let decoder = decoder::detect(&mut headers, body::wrap(res.body()), gzip); let decoder = decoder::detect(&mut headers, body::wrap(res.into_body()), gzip);
debug!("Response: '{}' for {}", status, url); debug!("Response: '{}' for {}", status, url);
Response { Response {
status: status, status: status,

View File

@@ -3,9 +3,9 @@ use std::fmt;
use std::io::{self, Cursor, Read}; use std::io::{self, Cursor, Read};
use bytes::Bytes; use bytes::Bytes;
use hyper::{self, Chunk}; use hyper::{self};
use {async_impl, wait}; use {async_impl};
/// The body of a `Request`. /// The body of a `Request`.
/// ///
@@ -184,7 +184,7 @@ impl Read for Reader {
pub struct Sender { pub struct Sender {
body: (Box<Read + Send>, Option<u64>), body: (Box<Read + Send>, Option<u64>),
tx: wait::WaitSink<::futures::sync::mpsc::Sender<hyper::Result<Chunk>>>, tx: hyper::body::Sender,
} }
impl Sender { impl Sender {
@@ -201,13 +201,8 @@ impl Sender {
Ok(0) => return Ok(()), Ok(0) => return Ok(()),
Ok(n) => { Ok(n) => {
unsafe { buf.advance_mut(n); } unsafe { buf.advance_mut(n); }
if let Err(e) = tx.send(Ok(buf.take().freeze().into())) { if let Err(_) = tx.send_data(buf.take().freeze().into()) {
if let wait::Waited::Err(_) = e { return Err(::error::timedout(None));
let epipe = io::Error::new(io::ErrorKind::BrokenPipe, "broken pipe");
return Err(::error::from(epipe));
} else {
return Err(::error::timedout(None));
}
} }
if buf.remaining_mut() == 0 { if buf.remaining_mut() == 0 {
buf.reserve(8192); buf.reserve(8192);
@@ -215,7 +210,7 @@ impl Sender {
} }
Err(e) => { Err(e) => {
let ret = io::Error::new(e.kind(), e.to_string()); let ret = io::Error::new(e.kind(), e.to_string());
let _ = tx.send(Err(e.into())); tx.abort();
return Err(::error::from(ret)); return Err(::error::from(ret));
} }
} }
@@ -227,10 +222,10 @@ impl Sender {
pub fn async(body: Body) -> (Option<Sender>, async_impl::Body, Option<u64>) { pub fn async(body: Body) -> (Option<Sender>, async_impl::Body, Option<u64>) {
match body.kind { match body.kind {
Kind::Reader(read, len) => { Kind::Reader(read, len) => {
let (tx, rx) = hyper::Body::pair(); let (tx, rx) = hyper::Body::channel();
let tx = Sender { let tx = Sender {
body: (read, len), body: (read, len),
tx: wait::sink(tx, None), tx: tx,
}; };
(Some(tx), async_impl::body::wrap(rx), len) (Some(tx), async_impl::body::wrap(rx), len)
}, },

View File

@@ -174,8 +174,8 @@ impl ClientBuilder {
/// ```rust /// ```rust
/// use reqwest::header; /// use reqwest::header;
/// # fn build_client() -> Result<(), Box<std::error::Error>> { /// # fn build_client() -> Result<(), Box<std::error::Error>> {
/// let mut headers = header::Headers::new(); /// let mut headers = header::HeaderMap::new();
/// headers.set(header::Authorization("secret".to_string())); /// headers.insert(header::AUTHORIZATION, header::HeaderValue::from_static("secret"));
/// ///
/// // get a client builder /// // get a client builder
/// let client = reqwest::Client::builder() /// let client = reqwest::Client::builder()
@@ -191,8 +191,8 @@ impl ClientBuilder {
/// ```rust /// ```rust
/// use reqwest::header; /// use reqwest::header;
/// # fn build_client() -> Result<(), Box<std::error::Error>> { /// # fn build_client() -> Result<(), Box<std::error::Error>> {
/// let mut headers = header::Headers::new(); /// let mut headers = header::HeaderMap::new();
/// headers.set(header::Authorization("secret".to_string())); /// headers.insert(header::AUTHORIZATION, header::HeaderValue::from_static("secret"));
/// ///
/// // get a client builder /// // get a client builder
/// let client = reqwest::Client::builder() /// let client = reqwest::Client::builder()
@@ -200,13 +200,13 @@ impl ClientBuilder {
/// .build()?; /// .build()?;
/// let res = client /// let res = client
/// .get("https://www.rust-lang.org") /// .get("https://www.rust-lang.org")
/// .header(header::Authorization("token".to_string())) /// .header(header::AUTHORIZATION, "token")
/// .send()?; /// .send()?;
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[inline] #[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.inner.default_headers(headers);
self self
} }
@@ -287,7 +287,7 @@ impl Client {
/// ///
/// This method fails whenever supplied `Url` cannot be parsed. /// This method fails whenever supplied `Url` cannot be parsed.
pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder { pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder {
self.request(Method::Get, url) self.request(Method::GET, url)
} }
/// Convenience method to make a `POST` request to a 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. /// This method fails whenever supplied `Url` cannot be parsed.
pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder { pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder {
self.request(Method::Post, url) self.request(Method::POST, url)
} }
/// Convenience method to make a `PUT` request to a 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. /// This method fails whenever supplied `Url` cannot be parsed.
pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder { pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder {
self.request(Method::Put, url) self.request(Method::PUT, url)
} }
/// Convenience method to make a `PATCH` request to a 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. /// This method fails whenever supplied `Url` cannot be parsed.
pub fn patch<U: IntoUrl>(&self, url: U) -> RequestBuilder { pub fn patch<U: IntoUrl>(&self, url: U) -> RequestBuilder {
self.request(Method::Patch, url) self.request(Method::PATCH, url)
} }
/// Convenience method to make a `DELETE` request to a 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. /// This method fails whenever supplied `Url` cannot be parsed.
pub fn delete<U: IntoUrl>(&self, url: U) -> RequestBuilder { pub fn delete<U: IntoUrl>(&self, url: U) -> RequestBuilder {
self.request(Method::Delete, url) self.request(Method::DELETE, url)
} }
/// Convenience method to make a `HEAD` request to a 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. /// This method fails whenever supplied `Url` cannot be parsed.
pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder { pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder {
self.request(Method::Head, url) self.request(Method::HEAD, url)
} }
/// Start building a `Request` with the `Method` and `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 mut builder = async_impl::client::take_builder(&mut builder.inner);
let (tx, rx) = mpsc::unbounded(); let (tx, rx) = mpsc::unbounded();
let (spawn_tx, spawn_rx) = oneshot::channel::<::Result<()>>(); let (spawn_tx, spawn_rx) = oneshot::channel::<::Result<()>>();
let handle = try_!(thread::Builder::new().name("reqwest-internal-sync-core".into()).spawn(move || { let handle = try_!(thread::Builder::new().name("reqwest-internal-sync-runtime".into()).spawn(move || {
use tokio_core::reactor::Core; use tokio::runtime::current_thread::Runtime;
let built = (|| { let built = (|| {
let core = try_!(Core::new()); let rt = try_!(Runtime::new());
let handle = core.handle(); let client = builder.build()?;
let client = builder.build(&handle)?; Ok((rt, client))
Ok((core, handle, client))
})(); })();
let (mut core, handle, client) = match built { let (mut rt, client) = match built {
Ok((a, b, c)) => { Ok((rt, c)) => {
if let Err(_) = spawn_tx.send(Ok(())) { if let Err(_) = spawn_tx.send(Ok(())) {
return; return;
} }
(a, b, c) (rt, c)
}, },
Err(e) => { Err(e) => {
let _ = spawn_tx.send(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<async_impl::Response>> = tx; let tx: oneshot::Sender<::Result<async_impl::Response>> = tx;
let task = client.execute(req) let task = client.execute(req)
.then(move |x| tx.send(x).map_err(|_| ())); .then(move |x| tx.send(x).map_err(|_| ()));
handle.spawn(task); ::tokio::spawn(task);
Ok(()) Ok(())
}); });
// work is Future<(), ()>, and our closure will never return Err // 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 { let inner_handle = Arc::new(InnerClientHandle {
tx: Some(tx), tx: Some(tx),

View File

@@ -1,10 +1,10 @@
use bytes::{Buf, BufMut, IntoBuf}; use bytes::{Buf, BufMut, IntoBuf};
use futures::{Async, Future, Poll}; use futures::{Async, Future, Poll};
use hyper::client::{HttpConnector, Service}; use http::uri::Scheme;
use hyper::Uri; use hyper::client::{HttpConnector};
use hyper::client::connect::{Connect, Connected, Destination};
use hyper_tls::{HttpsConnector, MaybeHttpsStream}; use hyper_tls::{HttpsConnector, MaybeHttpsStream};
use native_tls::TlsConnector; use native_tls::TlsConnector;
use tokio_core::reactor::Handle;
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use tokio_tls::{TlsConnectorExt, TlsStream}; use tokio_tls::{TlsConnectorExt, TlsStream};
@@ -22,8 +22,8 @@ pub struct Connector {
} }
impl Connector { impl Connector {
pub fn new(threads: usize, tls: TlsConnector, proxies: Arc<Vec<Proxy>>, handle: &Handle) -> Connector { pub fn new(threads: usize, tls: TlsConnector, proxies: Arc<Vec<Proxy>>) -> Connector {
let mut http = HttpConnector::new(threads, handle); let mut http = HttpConnector::new(threads);
http.enforce_http(false); http.enforce_http(false);
let https = HttpsConnector::from((http, tls.clone())); let https = HttpsConnector::from((http, tls.clone()));
@@ -39,41 +39,53 @@ impl Connector {
} }
} }
impl Service for Connector { impl Connect for Connector {
type Request = Uri; type Transport = Conn;
type Response = Conn;
type Error = io::Error; type Error = io::Error;
type Future = Connecting; type Future = Connecting;
fn call(&self, uri: Uri) -> Self::Future { fn connect(&self, dst: Destination) -> Self::Future {
for prox in self.proxies.iter() { for prox in self.proxies.iter() {
if let Some(puri) = proxy::intercept(prox, &uri) { if let Some(puri) = proxy::intercept(prox, &dst) {
trace!("proxy({:?}) intercepts {:?}", puri, uri); trace!("proxy({:?}) intercepts {:?}", puri, dst);
if uri.scheme() == Some("https") { let mut ndst = dst.clone();
let host = uri.host().unwrap().to_owned(); let new_scheme = puri
let port = uri.port().unwrap_or(443); .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(); 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"); trace!("tunneling HTTPS over proxy");
tunnel(conn, host.clone(), port) tunnel(conn, host.clone(), port)
.and_then(move |tunneled| { .and_then(move |tunneled| {
tls.connect_async(&host, tunneled) tls.connect_async(&host, tunneled)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e)) .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 = <HttpConnector as Service>::Response; type HttpStream = <HttpConnector as Connect>::Transport;
type HttpsStream = MaybeHttpsStream<HttpStream>; type HttpsStream = MaybeHttpsStream<HttpStream>;
pub type Connecting = Box<Future<Item=Conn, Error=io::Error>>; pub type Connecting = Box<Future<Item=(Conn, Connected), Error=io::Error> + Send>;
pub enum Conn { pub enum Conn {
Normal(HttpsStream), Normal(HttpsStream),
@@ -214,8 +226,8 @@ mod tests {
use std::net::TcpListener; use std::net::TcpListener;
use std::thread; use std::thread;
use futures::Future; use futures::Future;
use tokio_core::reactor::Core; use tokio::runtime::current_thread::Runtime;
use tokio_core::net::TcpStream; use tokio::net::TcpStream;
use super::tunnel; use super::tunnel;
@@ -251,44 +263,44 @@ mod tests {
fn test_tunnel() { fn test_tunnel() {
let addr = mock_tunnel!(); let addr = mock_tunnel!();
let mut core = Core::new().unwrap(); let mut rt = Runtime::new().unwrap();
let work = TcpStream::connect(&addr, &core.handle()); let work = TcpStream::connect(&addr);
let host = addr.ip().to_string(); let host = addr.ip().to_string();
let port = addr.port(); let port = addr.port();
let work = work.and_then(|tcp| { let work = work.and_then(|tcp| {
tunnel(tcp, host, port) tunnel(tcp, host, port)
}); });
core.run(work).unwrap(); rt.block_on(work).unwrap();
} }
#[test] #[test]
fn test_tunnel_eof() { fn test_tunnel_eof() {
let addr = mock_tunnel!(b"HTTP/1.1 200 OK"); let addr = mock_tunnel!(b"HTTP/1.1 200 OK");
let mut core = Core::new().unwrap(); let mut rt = Runtime::new().unwrap();
let work = TcpStream::connect(&addr, &core.handle()); let work = TcpStream::connect(&addr);
let host = addr.ip().to_string(); let host = addr.ip().to_string();
let port = addr.port(); let port = addr.port();
let work = work.and_then(|tcp| { let work = work.and_then(|tcp| {
tunnel(tcp, host, port) tunnel(tcp, host, port)
}); });
core.run(work).unwrap_err(); rt.block_on(work).unwrap_err();
} }
#[test] #[test]
fn test_tunnel_bad_response() { fn test_tunnel_bad_response() {
let addr = mock_tunnel!(b"foo bar baz hallo"); let addr = mock_tunnel!(b"foo bar baz hallo");
let mut core = Core::new().unwrap(); let mut rt = Runtime::new().unwrap();
let work = TcpStream::connect(&addr, &core.handle()); let work = TcpStream::connect(&addr);
let host = addr.ip().to_string(); let host = addr.ip().to_string();
let port = addr.port(); let port = addr.port();
let work = work.and_then(|tcp| { let work = work.and_then(|tcp| {
tunnel(tcp, host, port) tunnel(tcp, host, port)
}); });
core.run(work).unwrap_err(); rt.block_on(work).unwrap_err();
} }
} }

View File

@@ -112,6 +112,7 @@ impl Error {
pub fn get_ref(&self) -> Option<&(StdError + Send + Sync + 'static)> { pub fn get_ref(&self) -> Option<&(StdError + Send + Sync + 'static)> {
match self.kind { match self.kind {
Kind::Http(ref e) => Some(e), Kind::Http(ref e) => Some(e),
Kind::Hyper(ref e) => Some(e),
Kind::Url(ref e) => Some(e), Kind::Url(ref e) => Some(e),
Kind::Tls(ref e) => Some(e), Kind::Tls(ref e) => Some(e),
Kind::Io(ref e) => Some(e), Kind::Io(ref e) => Some(e),
@@ -129,6 +130,7 @@ impl Error {
pub fn is_http(&self) -> bool { pub fn is_http(&self) -> bool {
match self.kind { match self.kind {
Kind::Http(_) => true, Kind::Http(_) => true,
Kind::Hyper(_) => true,
_ => false, _ => false,
} }
} }
@@ -190,6 +192,7 @@ impl fmt::Display for Error {
} }
match self.kind { match self.kind {
Kind::Http(ref e) => fmt::Display::fmt(e, f), 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::Url(ref e) => fmt::Display::fmt(e, f),
Kind::Tls(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), Kind::Io(ref e) => fmt::Display::fmt(e, f),
@@ -213,6 +216,7 @@ impl StdError for Error {
fn description(&self) -> &str { fn description(&self) -> &str {
match self.kind { match self.kind {
Kind::Http(ref e) => e.description(), Kind::Http(ref e) => e.description(),
Kind::Hyper(ref e) => e.description(),
Kind::Url(ref e) => e.description(), Kind::Url(ref e) => e.description(),
Kind::Tls(ref e) => e.description(), Kind::Tls(ref e) => e.description(),
Kind::Io(ref e) => e.description(), Kind::Io(ref e) => e.description(),
@@ -228,6 +232,7 @@ impl StdError for Error {
fn cause(&self) -> Option<&StdError> { fn cause(&self) -> Option<&StdError> {
match self.kind { match self.kind {
Kind::Http(ref e) => e.cause(), Kind::Http(ref e) => e.cause(),
Kind::Hyper(ref e) => e.cause(),
Kind::Url(ref e) => e.cause(), Kind::Url(ref e) => e.cause(),
Kind::Tls(ref e) => e.cause(), Kind::Tls(ref e) => e.cause(),
Kind::Io(ref e) => e.cause(), Kind::Io(ref e) => e.cause(),
@@ -245,7 +250,8 @@ impl StdError for Error {
#[derive(Debug)] #[derive(Debug)]
pub enum Kind { pub enum Kind {
Http(::hyper::Error), Http(::http::Error),
Hyper(::hyper::Error),
Url(::url::ParseError), Url(::url::ParseError),
Tls(::native_tls::Error), Tls(::native_tls::Error),
Io(io::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 { impl From<::hyper::Error> for Kind {
#[inline] #[inline]
fn from(err: ::hyper::Error) -> Kind { fn from(err: ::hyper::Error) -> Kind {
match err { match err {
::hyper::Error::Io(err) => Kind::Io(err), other => Kind::Hyper(other),
//::hyper::Error::Uri(err) => Kind::Url(err),
other => Kind::Http(other),
} }
} }
} }
@@ -430,20 +441,6 @@ pub fn server_error(url: Url, status: StatusCode) -> Error {
mod tests { mod tests {
use super::*; 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] #[test]
fn test_cause_chain() { fn test_cause_chain() {
#[derive(Debug)] #[derive(Debug)]
@@ -476,9 +473,6 @@ mod tests {
} }
} }
let err = from(::hyper::Error::Status);
assert!(err.cause().is_none());
let root = Chain(None::<Error>); let root = Chain(None::<Error>);
let io = ::std::io::Error::new(::std::io::ErrorKind::Other, root); let io = ::std::io::Error::new(::std::io::ErrorKind::Other, root);
let err = Error { kind: Kind::Io(io), url: None }; let err = Error { kind: Kind::Io(io), url: None };

View File

@@ -36,7 +36,3 @@ impl<'a> PolyfillTryInto for &'a String {
pub fn to_uri(url: &Url) -> ::hyper::Uri { pub fn to_uri(url: &Url) -> ::hyper::Uri {
url.as_str().parse().expect("a parsed Url should always be a valid 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")
}

View File

@@ -124,15 +124,18 @@
//! [serde]: http://serde.rs //! [serde]: http://serde.rs
//! [cookiejar_issue]: https://github.com/seanmonstar/reqwest/issues/14 //! [cookiejar_issue]: https://github.com/seanmonstar/reqwest/issues/14
extern crate base64;
extern crate bytes; extern crate bytes;
extern crate encoding_rs; extern crate encoding_rs;
#[macro_use] #[macro_use]
extern crate futures; extern crate futures;
extern crate http;
extern crate hyper; extern crate hyper;
extern crate hyper_tls; extern crate hyper_tls;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate libflate; extern crate libflate;
extern crate mime;
extern crate mime_guess; extern crate mime_guess;
extern crate native_tls; extern crate native_tls;
extern crate serde; extern crate serde;
@@ -141,14 +144,13 @@ extern crate serde;
extern crate serde_derive; extern crate serde_derive;
extern crate serde_json; extern crate serde_json;
extern crate serde_urlencoded; extern crate serde_urlencoded;
extern crate tokio_core; extern crate tokio;
extern crate tokio_io; extern crate tokio_io;
extern crate tokio_tls; extern crate tokio_tls;
extern crate url; extern crate url;
extern crate uuid; extern crate uuid;
pub use hyper::header; pub use hyper::header;
pub use hyper::mime;
pub use hyper::Method; pub use hyper::Method;
pub use hyper::StatusCode; pub use hyper::StatusCode;
pub use url::Url; pub use url::Url;

View File

@@ -4,8 +4,7 @@ use std::fs::File;
use std::io::{self, Cursor, Read}; use std::io::{self, Cursor, Read};
use std::path::Path; use std::path::Path;
use mime::Mime; use mime_guess::{self, Mime};
use mime_guess;
use url::percent_encoding; use url::percent_encoding;
use uuid::Uuid; use uuid::Uuid;

View File

@@ -1,7 +1,7 @@
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
use hyper::Uri; use hyper::client::connect::Destination;
use {into_url, IntoUrl, Url}; use {into_url, IntoUrl, Url};
/// Configuration of a proxy that a `Client` should pass requests to. /// Configuration of a proxy that a `Client` should pass requests to.
@@ -128,36 +128,36 @@ impl Proxy {
} }
} }
fn proxies(&self, url: &Url) -> bool { fn intercept<D: Dst>(&self, uri: &D) -> Option<::hyper::Uri> {
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<Uri> {
match self.intercept { match self.intercept {
Intercept::All(ref u) => Some(u.clone()), Intercept::All(ref u) => Some(u.clone()),
Intercept::Http(ref u) => { Intercept::Http(ref u) => {
if uri.scheme() == Some("http") { if uri.scheme() == "http" {
Some(u.clone()) Some(u.clone())
} else { } else {
None None
} }
}, },
Intercept::Https(ref u) => { Intercept::Https(ref u) => {
if uri.scheme() == Some("https") { if uri.scheme() == "https" {
Some(u.clone()) Some(u.clone())
} else { } else {
None None
} }
}, },
Intercept::Custom(ref fun) => { Intercept::Custom(ref fun) => {
(fun.0)(&into_url::to_url(uri)) (fun.0)(
.map(|u| into_url::to_uri(&u)) &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)] #[derive(Clone, Debug)]
enum Intercept { enum Intercept {
All(Uri), All(::hyper::Uri),
Http(Uri), Http(::hyper::Uri),
Https(Uri), Https(::hyper::Uri),
Custom(Custom), Custom(Custom),
} }
@@ -182,20 +182,50 @@ impl fmt::Debug for Custom {
// pub(crate) // pub(crate)
pub fn intercept(proxy: &Proxy, uri: &Uri) -> Option<Uri> { /// A helper trait to allow testing `Proxy::intercept` without having to
proxy.intercept(uri) /// construct `hyper::client::connect::Destination`s.
trait Dst {
fn scheme(&self) -> &str;
fn host(&self) -> &str;
fn port(&self) -> Option<u16>;
} }
pub fn is_proxied(proxies: &[Proxy], uri: &Url) -> bool { #[doc(hidden)]
proxies.iter().any(|p| p.proxies(uri)) impl Dst for Destination {
fn scheme(&self) -> &str {
Destination::scheme(self)
}
fn host(&self) -> &str {
Destination::host(self)
}
fn port(&self) -> Option<u16> {
Destination::port(self)
}
}
pub fn intercept(proxy: &Proxy, uri: &Destination) -> Option<::http::Uri> {
proxy.intercept(uri)
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
fn uri(s: &str) -> Uri { impl Dst for Url {
s.parse().unwrap() fn scheme(&self) -> &str {
Url::scheme(self)
}
fn host(&self) -> &str {
Url::host_str(self)
.expect("<Url as Dst>::host should have a str")
}
fn port(&self) -> Option<u16> {
Url::port(self)
}
} }
fn url(s: &str) -> Url { fn url(s: &str) -> Url {
@@ -210,10 +240,8 @@ mod tests {
let http = "http://hyper.rs"; let http = "http://hyper.rs";
let other = "https://hyper.rs"; let other = "https://hyper.rs";
assert!(p.proxies(&url(http))); assert_eq!(p.intercept(&url(http)).unwrap(), target);
assert_eq!(p.intercept(&uri(http)).unwrap(), target); assert!(p.intercept(&url(other)).is_none());
assert!(!p.proxies(&url(other)));
assert!(p.intercept(&uri(other)).is_none());
} }
#[test] #[test]
@@ -224,10 +252,8 @@ mod tests {
let http = "http://hyper.rs"; let http = "http://hyper.rs";
let other = "https://hyper.rs"; let other = "https://hyper.rs";
assert!(!p.proxies(&url(http))); assert!(p.intercept(&url(http)).is_none());
assert!(p.intercept(&uri(http)).is_none()); assert_eq!(p.intercept(&url(other)).unwrap(), target);
assert!(p.proxies(&url(other)));
assert_eq!(p.intercept(&uri(other)).unwrap(), target);
} }
#[test] #[test]
@@ -239,13 +265,9 @@ mod tests {
let https = "https://hyper.rs"; let https = "https://hyper.rs";
let other = "x-youve-never-heard-of-me-mr-proxy://hyper.rs"; let other = "x-youve-never-heard-of-me-mr-proxy://hyper.rs";
assert!(p.proxies(&url(http))); assert_eq!(p.intercept(&url(http)).unwrap(), target);
assert!(p.proxies(&url(https))); assert_eq!(p.intercept(&url(https)).unwrap(), target);
assert!(p.proxies(&url(other))); assert_eq!(p.intercept(&url(other)).unwrap(), target);
assert_eq!(p.intercept(&uri(http)).unwrap(), target);
assert_eq!(p.intercept(&uri(https)).unwrap(), target);
assert_eq!(p.intercept(&uri(other)).unwrap(), target);
} }
@@ -267,29 +289,9 @@ mod tests {
let https = "https://hyper.rs"; let https = "https://hyper.rs";
let other = "x-youve-never-heard-of-me-mr-proxy://seanmonstar.com"; let other = "x-youve-never-heard-of-me-mr-proxy://seanmonstar.com";
assert!(p.proxies(&url(http))); assert_eq!(p.intercept(&url(http)).unwrap(), target2);
assert!(p.proxies(&url(https))); assert_eq!(p.intercept(&url(https)).unwrap(), target1);
assert!(!p.proxies(&url(other))); assert!(p.intercept(&url(other)).is_none());
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));
} }
} }

View File

@@ -1,6 +1,6 @@
use std::fmt; use std::fmt;
use hyper::header::Headers; use header::HeaderMap;
use hyper::StatusCode; use hyper::StatusCode;
use Url; use Url;
@@ -228,15 +228,15 @@ pub fn check_redirect(
.inner .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() { if let Some(previous) = previous.last() {
let cross_host = next.host_str() != previous.host_str() || let cross_host = next.host_str() != previous.host_str() ||
next.port_or_known_default() != previous.port_or_known_default(); next.port_or_known_default() != previous.port_or_known_default();
if cross_host { if cross_host {
headers.remove_raw("authorization"); headers.remove("authorization");
headers.remove_raw("cookie"); headers.remove("cookie");
headers.remove_raw("cookie2"); headers.remove("cookie2");
headers.remove_raw("www-authenticate"); headers.remove("www-authenticate");
} }
} }
} }
@@ -268,14 +268,14 @@ fn test_redirect_policy_limit() {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
assert_eq!( assert_eq!(
check_redirect(&policy, StatusCode::Found, &next, &previous), check_redirect(&policy, StatusCode::FOUND, &next, &previous),
Action::Follow Action::Follow
); );
previous.push(Url::parse("http://a.b.d/e/33").unwrap()); previous.push(Url::parse("http://a.b.d/e/33").unwrap());
assert_eq!( assert_eq!(
check_redirect(&policy, StatusCode::Found, &next, &previous), check_redirect(&policy, StatusCode::FOUND, &next, &previous),
Action::TooManyRedirects Action::TooManyRedirects
); );
} }
@@ -292,27 +292,25 @@ fn test_redirect_policy_custom() {
let next = Url::parse("http://bar/baz").unwrap(); let next = Url::parse("http://bar/baz").unwrap();
assert_eq!( assert_eq!(
check_redirect(&policy, StatusCode::Found, &next, &[]), check_redirect(&policy, StatusCode::FOUND, &next, &[]),
Action::Follow Action::Follow
); );
let next = Url::parse("http://foo/baz").unwrap(); let next = Url::parse("http://foo/baz").unwrap();
assert_eq!( assert_eq!(
check_redirect(&policy, StatusCode::Found, &next, &[]), check_redirect(&policy, StatusCode::FOUND, &next, &[]),
Action::Stop Action::Stop
); );
} }
#[test] #[test]
fn test_remove_sensitive_headers() { fn test_remove_sensitive_headers() {
use hyper::header::{Accept, Authorization, Cookie}; use hyper::header::{ACCEPT, AUTHORIZATION, COOKIE, HeaderValue};
let mut headers = Headers::new(); let mut headers = HeaderMap::new();
headers.set(Accept::star()); headers.insert(ACCEPT, HeaderValue::from_static("*/*"));
headers.set(Authorization("let me in".to_owned())); headers.insert(AUTHORIZATION, HeaderValue::from_static("let me in"));
let mut cookie = Cookie::new(); headers.insert(COOKIE, HeaderValue::from_static("foo=bar"));
cookie.set("foo", "bar");
headers.set(cookie);
let next = Url::parse("http://initial-domain.com/path").unwrap(); let next = Url::parse("http://initial-domain.com/path").unwrap();
let mut prev = vec![Url::parse("http://initial-domain.com/new_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); assert_eq!(headers, filtered_headers);
prev.push(Url::parse("http://new-domain.com/path").unwrap()); prev.push(Url::parse("http://new-domain.com/path").unwrap());
filtered_headers.remove::<Authorization<String>>(); filtered_headers.remove(AUTHORIZATION);
filtered_headers.remove::<Cookie>(); filtered_headers.remove(COOKIE);
remove_sensitive_headers(&mut headers, &next, &prev); remove_sensitive_headers(&mut headers, &next, &prev);
assert_eq!(headers, filtered_headers); assert_eq!(headers, filtered_headers);

View File

@@ -1,12 +1,13 @@
use std::fmt; use std::fmt;
use hyper::header::ContentType; use base64::encode;
use serde::Serialize; use serde::Serialize;
use serde_json; use serde_json;
use serde_urlencoded; use serde_urlencoded;
use body::{self, Body}; use body::{self, Body};
use header::Headers; use header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE};
use http::HttpTryFrom;
use {async_impl, Client, Method, Url}; use {async_impl, Client, Method, Url};
/// A request which can be executed with `Client::execute()`. /// A request which can be executed with `Client::execute()`.
@@ -58,13 +59,13 @@ impl Request {
/// Get the headers. /// Get the headers.
#[inline] #[inline]
pub fn headers(&self) -> &Headers { pub fn headers(&self) -> &HeaderMap {
self.inner.headers() self.inner.headers()
} }
/// Get a mutable reference to the headers. /// Get a mutable reference to the headers.
#[inline] #[inline]
pub fn headers_mut(&mut self) -> &mut Headers { pub fn headers_mut(&mut self) -> &mut HeaderMap {
self.inner.headers_mut() self.inner.headers_mut()
} }
@@ -85,22 +86,31 @@ impl RequestBuilder {
/// Add a `Header` to this Request. /// Add a `Header` to this Request.
/// ///
/// ```rust /// ```rust
/// use reqwest::header::UserAgent; /// use reqwest::header::USER_AGENT;
/// ///
/// # fn run() -> Result<(), Box<::std::error::Error>> { /// # fn run() -> Result<(), Box<::std::error::Error>> {
/// let client = reqwest::Client::new(); /// let client = reqwest::Client::new();
/// let res = client.get("https://www.rust-lang.org") /// let res = client.get("https://www.rust-lang.org")
/// .header(UserAgent::new("foo")) /// .header(USER_AGENT, "foo")
/// .send()?; /// .send()?;
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
pub fn header<H>(&mut self, header: H) -> &mut RequestBuilder pub fn header<K, V>(&mut self, key: K, value: V) -> &mut RequestBuilder
where where
H: ::header::Header, HeaderName: HttpTryFrom<K>,
HeaderValue: HttpTryFrom<V>,
{ {
if let Some(req) = request_mut(&mut self.request, &self.err) { if let Some(req) = request_mut(&mut self.request, &self.err) {
req.headers_mut().set(header); match <HeaderName as HttpTryFrom<K>>::try_from(key) {
Ok(key) => {
match <HeaderValue as HttpTryFrom<V>>::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 self
} }
@@ -110,13 +120,13 @@ impl RequestBuilder {
/// The headers will be merged in to any already set. /// The headers will be merged in to any already set.
/// ///
/// ```rust /// ```rust
/// use reqwest::header::{Headers, UserAgent, ContentType}; /// use reqwest::header::{HeaderMap, HeaderValue, USER_AGENT, CONTENT_TYPE};
/// # use std::fs; /// # use std::fs;
/// ///
/// fn construct_headers() -> Headers { /// fn construct_headers() -> HeaderMap {
/// let mut headers = Headers::new(); /// let mut headers = HeaderMap::new();
/// headers.set(UserAgent::new("reqwest")); /// headers.insert(USER_AGENT, HeaderValue::from_static("reqwest"));
/// headers.set(ContentType::png()); /// headers.insert(CONTENT_TYPE, HeaderValue::from_static("image/png"));
/// headers /// headers
/// } /// }
/// ///
@@ -130,9 +140,11 @@ impl RequestBuilder {
/// # Ok(()) /// # 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) { 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 self
} }
@@ -153,10 +165,10 @@ impl RequestBuilder {
U: Into<String>, U: Into<String>,
P: Into<String>, P: Into<String>,
{ {
self.header(::header::Authorization(::header::Basic { let username = username.into();
username: username.into(), let password = password.map(|p| p.into()).unwrap_or(String::new());
password: password.map(|p| p.into()), let header_value = format!("basic {}:{}", username, encode(&password));
})) self.header(::header::AUTHORIZATION, HeaderValue::from_str(header_value.as_str()).expect(""))
} }
/// Set the request body. /// Set the request body.
@@ -283,7 +295,7 @@ impl RequestBuilder {
if let Some(req) = request_mut(&mut self.request, &self.err) { if let Some(req) = request_mut(&mut self.request, &self.err) {
match serde_urlencoded::to_string(form) { match serde_urlencoded::to_string(form) {
Ok(body) => { 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()); *req.body_mut() = Some(body.into());
}, },
Err(err) => self.err = Some(::error::from(err)), 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) { if let Some(req) = request_mut(&mut self.request, &self.err) {
match serde_json::to_vec(json) { match serde_json::to_vec(json) {
Ok(body) => { 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()); *req.body_mut() = Some(body.into());
}, },
Err(err) => self.err = Some(::error::from(err)), Err(err) => self.err = Some(::error::from(err)),
@@ -333,7 +345,6 @@ impl RequestBuilder {
/// Sends a multipart/form-data body. /// Sends a multipart/form-data body.
/// ///
/// ``` /// ```
/// use reqwest::mime;
/// # use reqwest::Error; /// # use reqwest::Error;
/// ///
/// # fn run() -> Result<(), Box<std::error::Error>> { /// # fn run() -> Result<(), Box<std::error::Error>> {
@@ -352,10 +363,14 @@ impl RequestBuilder {
/// See [`multipart`](multipart/) for more examples. /// See [`multipart`](multipart/) for more examples.
pub fn multipart(&mut self, mut multipart: ::multipart::Form) -> &mut RequestBuilder { pub fn multipart(&mut self, mut multipart: ::multipart::Form) -> &mut RequestBuilder {
if let Some(req) = request_mut(&mut self.request, &self.err) { if let Some(req) = request_mut(&mut self.request, &self.err) {
req.headers_mut().set( req.headers_mut().insert(
::header::ContentType(format!("multipart/form-data; boundary={}", ::multipart_::boundary(&multipart)) ::header::CONTENT_TYPE,
.parse().unwrap() HeaderValue::from_str(
) format!(
"multipart/form-data; boundary={}",
::multipart_::boundary(&multipart)
).as_str()
).expect("")
); );
*req.body_mut() = Some(match ::multipart_::compute_length(&mut multipart) { *req.body_mut() = Some(match ::multipart_::compute_length(&mut multipart) {
Some(length) => Body::sized(::multipart_::reader(multipart), length), Some(length) => Body::sized(::multipart_::reader(multipart), length),
@@ -450,13 +465,13 @@ pub fn builder(client: Client, req: ::Result<Request>) -> RequestBuilder {
#[inline] #[inline]
pub fn async(req: Request) -> (async_impl::Request, Option<body::Sender>) { pub fn async(req: Request) -> (async_impl::Request, Option<body::Sender>) {
use header::ContentLength; use header::CONTENT_LENGTH;
let mut req_async = req.inner; let mut req_async = req.inner;
let body = req.body.and_then(|body| { let body = req.body.and_then(|body| {
let (tx, body, len) = body::async(body); let (tx, body, len) = body::async(body);
if let Some(len) = len { 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); *req_async.body_mut() = Some(body);
tx tx
@@ -467,7 +482,7 @@ pub fn async(req: Request) -> (async_impl::Request, Option<body::Sender>) {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use {body, Client, Method}; use {body, Client, Method};
use header::{Host, Headers, ContentType}; use header::{HOST, HeaderMap, HeaderValue, CONTENT_TYPE};
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use serde_json; use serde_json;
use serde_urlencoded; use serde_urlencoded;
@@ -478,7 +493,7 @@ mod tests {
let some_url = "https://google.com/"; let some_url = "https://google.com/";
let r = client.get(some_url).build().unwrap(); 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); assert_eq!(r.url().as_str(), some_url);
} }
@@ -488,7 +503,7 @@ mod tests {
let some_url = "https://google.com/"; let some_url = "https://google.com/";
let r = client.head(some_url).build().unwrap(); 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); assert_eq!(r.url().as_str(), some_url);
} }
@@ -498,7 +513,7 @@ mod tests {
let some_url = "https://google.com/"; let some_url = "https://google.com/";
let r = client.post(some_url).build().unwrap(); 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); assert_eq!(r.url().as_str(), some_url);
} }
@@ -508,7 +523,7 @@ mod tests {
let some_url = "https://google.com/"; let some_url = "https://google.com/";
let r = client.put(some_url).build().unwrap(); 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); assert_eq!(r.url().as_str(), some_url);
} }
@@ -518,7 +533,7 @@ mod tests {
let some_url = "https://google.com/"; let some_url = "https://google.com/";
let r = client.patch(some_url).build().unwrap(); 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); assert_eq!(r.url().as_str(), some_url);
} }
@@ -528,7 +543,7 @@ mod tests {
let some_url = "https://google.com/"; let some_url = "https://google.com/";
let r = client.delete(some_url).build().unwrap(); 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); assert_eq!(r.url().as_str(), some_url);
} }
@@ -538,13 +553,13 @@ mod tests {
let some_url = "https://google.com/"; let some_url = "https://google.com/";
let mut r = client.post(some_url); 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 // 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 // then check it was actually added
assert_eq!(r.headers().get::<Host>(), Some(&header)); assert_eq!(r.headers().get(HOST), Some(&header));
} }
#[test] #[test]
@@ -553,10 +568,10 @@ mod tests {
let some_url = "https://google.com/"; let some_url = "https://google.com/";
let mut r = client.post(some_url); 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(); let mut headers = HeaderMap::new();
headers.set(header); headers.insert(HOST, header);
// Add a copy of the headers to the request builder // Add a copy of the headers to the request builder
let r = r.headers(headers.clone()).build().unwrap(); let r = r.headers(headers.clone()).build().unwrap();
@@ -653,8 +668,7 @@ mod tests {
let mut r = r.form(&form_data).build().unwrap(); let mut r = r.form(&form_data).build().unwrap();
// Make sure the content type was set // Make sure the content type was set
assert_eq!(r.headers().get::<ContentType>(), assert_eq!(r.headers().get(CONTENT_TYPE).unwrap(), &"application/x-www-form-urlencoded");
Some(&ContentType::form_url_encoded()));
let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap(); 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(); let mut r = r.json(&json_data).build().unwrap();
// Make sure the content type was set // Make sure the content type was set
assert_eq!(r.headers().get::<ContentType>(), 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(); let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap();

View File

@@ -6,17 +6,19 @@ use std::borrow::Cow;
use encoding_rs::{Encoding, UTF_8}; use encoding_rs::{Encoding, UTF_8};
use futures::{Async, Poll, Stream}; use futures::{Async, Poll, Stream};
use mime::Mime;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde_json; use serde_json;
use client::KeepCoreThreadAlive; use client::KeepCoreThreadAlive;
use header::Headers; use hyper::header::HeaderMap;
use {async_impl, StatusCode, Url, wait}; use {async_impl, StatusCode, Url, wait};
/// A Response to a submitted `Request`. /// A Response to a submitted `Request`.
pub struct Response { pub struct Response {
inner: async_impl::Response, inner: async_impl::Response,
body: async_impl::ReadableChunks<WaitBody>, body: async_impl::ReadableChunks<WaitBody>,
content_length: Option<u64>,
_thread_handle: KeepCoreThreadAlive, _thread_handle: KeepCoreThreadAlive,
} }
@@ -70,8 +72,8 @@ impl Response {
/// .body("possibly too large") /// .body("possibly too large")
/// .send()?; /// .send()?;
/// match resp.status() { /// match resp.status() {
/// StatusCode::Ok => println!("success!"), /// StatusCode::OK => println!("success!"),
/// StatusCode::PayloadTooLarge => { /// StatusCode::PAYLOAD_TOO_LARGE => {
/// println!("Request payload is too large!"); /// println!("Request payload is too large!");
/// } /// }
/// s => println!("Received response status: {:?}", s), /// s => println!("Received response status: {:?}", s),
@@ -93,14 +95,15 @@ impl Response {
/// ```rust /// ```rust
/// # use std::io::{Read, Write}; /// # use std::io::{Read, Write};
/// # use reqwest::Client; /// # use reqwest::Client;
/// # use reqwest::header::ContentLength; /// # use reqwest::header::CONTENT_LENGTH;
/// # /// #
/// # fn run() -> Result<(), Box<::std::error::Error>> { /// # fn run() -> Result<(), Box<::std::error::Error>> {
/// let client = Client::new(); /// let client = Client::new();
/// let mut resp = client.head("http://httpbin.org/bytes/3000").send()?; /// let mut resp = client.head("http://httpbin.org/bytes/3000").send()?;
/// if resp.status().is_success() { /// if resp.status().is_success() {
/// let len = resp.headers().get::<ContentLength>() /// let len = resp.headers().get(CONTENT_LENGTH)
/// .map(|ct_len| **ct_len) /// .and_then(|ct_len| ct_len.to_str().ok())
/// .and_then(|ct_len| ct_len.parse().ok())
/// .unwrap_or(0); /// .unwrap_or(0);
/// // limit 1mb response /// // limit 1mb response
/// if len <= 1_000_000 { /// if len <= 1_000_000 {
@@ -115,7 +118,7 @@ impl Response {
/// # } /// # }
/// ``` /// ```
#[inline] #[inline]
pub fn headers(&self) -> &Headers { pub fn headers(&self) -> &HeaderMap {
self.inner.headers() self.inner.headers()
} }
@@ -189,14 +192,21 @@ impl Response {
/// This consumes the body. Trying to read more, or use of `response.json()` /// This consumes the body. Trying to read more, or use of `response.json()`
/// will return empty values. /// will return empty values.
pub fn text(&mut self) -> ::Result<String> { pub fn text(&mut self) -> ::Result<String> {
let len = self.headers().get::<::header::ContentLength>() let len = self.content_length.unwrap_or(0);
.map(|ct_len| **ct_len)
.unwrap_or(0);
let mut content = Vec::with_capacity(len as usize); let mut content = Vec::with_capacity(len as usize);
self.read_to_end(&mut content).map_err(::error::from)?; self.read_to_end(&mut content).map_err(::error::from)?;
let encoding_name = self.headers().get::<::header::ContentType>() let content_type = self.headers().get(::header::CONTENT_TYPE)
.and_then(|content_type| { .and_then(|value| {
content_type.get_param("charset") value.to_str().ok()
})
.and_then(|value| {
value.parse::<Mime>().ok()
});
let encoding_name = content_type
.as_ref()
.and_then(|mime| {
mime
.get_param("charset")
.map(|charset| charset.as_str()) .map(|charset| charset.as_str())
}) })
.unwrap_or("utf-8"); .unwrap_or("utf-8");
@@ -252,7 +262,7 @@ impl Response {
/// let res = reqwest::get("http://httpbin.org/status/400")? /// let res = reqwest::get("http://httpbin.org/status/400")?
/// .error_for_status(); /// .error_for_status();
/// if let Err(err) = res { /// if let Err(err) = res {
/// assert_eq!(err.status(), Some(reqwest::StatusCode::BadRequest)); /// assert_eq!(err.status(), Some(reqwest::StatusCode::BAD_REQUEST));
/// } /// }
/// # Ok(()) /// # Ok(())
/// # } /// # }
@@ -260,12 +270,13 @@ impl Response {
/// ``` /// ```
#[inline] #[inline]
pub fn error_for_status(self) -> ::Result<Self> { pub fn error_for_status(self) -> ::Result<Self> {
let Response { body, inner, _thread_handle } = self; let Response { body, content_length, inner, _thread_handle } = self;
inner.error_for_status().map(move |inner| { inner.error_for_status().map(move |inner| {
Response { Response {
inner: inner, inner,
body: body, body,
_thread_handle: _thread_handle, content_length,
_thread_handle,
} }
}) })
} }
@@ -306,6 +317,7 @@ impl Stream for WaitBody {
pub fn new(mut res: async_impl::Response, timeout: Option<Duration>, thread: KeepCoreThreadAlive) -> Response { pub fn new(mut res: async_impl::Response, timeout: Option<Duration>, thread: KeepCoreThreadAlive) -> Response {
let body = mem::replace(res.body_mut(), async_impl::Decoder::empty()); let body = mem::replace(res.body_mut(), async_impl::Decoder::empty());
let len = body.content_length();
let body = async_impl::ReadableChunks::new(WaitBody { let body = async_impl::ReadableChunks::new(WaitBody {
inner: wait::stream(body, timeout) inner: wait::stream(body, timeout)
}); });
@@ -313,6 +325,7 @@ pub fn new(mut res: async_impl::Response, timeout: Option<Duration>, thread: Kee
Response { Response {
inner: res, inner: res,
body: body, body: body,
content_length: len,
_thread_handle: thread, _thread_handle: thread,
} }
} }

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use std::thread; use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use futures::{Async, AsyncSink, Future, Sink, Stream}; use futures::{Async, Future, Stream};
use futures::executor::{self, Notify}; use futures::executor::{self, Notify};
// pub(crate) // pub(crate)
@@ -43,14 +43,6 @@ where S: Stream {
} }
} }
pub fn sink<S>(sink: S, timeout: Option<Duration>) -> WaitSink<S>
where S: Sink {
WaitSink {
sink: executor::spawn(sink),
timeout: timeout,
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum Waited<E> { pub enum Waited<E> {
TimedOut, TimedOut,
@@ -113,49 +105,6 @@ where S: Stream {
} }
} }
pub struct WaitSink<S> {
sink: executor::Spawn<S>,
timeout: Option<Duration>,
}
impl<S> WaitSink<S>
where S: Sink {
pub fn send(&mut self, mut item: S::SinkItem) -> Result<(), Waited<S::SinkError>> {
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, &notify, 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, &notify, 0)? {
AsyncSink::Ready => return Ok(()),
AsyncSink::NotReady(val) => val,
};
thread::park();
}
}
}
}
struct ThreadNotify { struct ThreadNotify {
thread: thread::Thread, thread: thread::Thread,
} }

View File

@@ -1,16 +1,15 @@
#![cfg(feature="unstable")] #![cfg(feature="unstable")]
extern crate futures; extern crate futures;
extern crate tokio_core;
extern crate reqwest;
extern crate libflate; extern crate libflate;
extern crate reqwest;
extern crate tokio;
#[macro_use] #[macro_use]
mod support; mod support;
use reqwest::unstable::async::Client; use reqwest::unstable::async::Client;
use futures::{Future, Stream}; use futures::{Future, Stream};
use tokio_core::reactor::Core;
use std::io::Write; use std::io::Write;
use std::time::Duration; use std::time::Duration;
@@ -46,10 +45,10 @@ fn test_gzip(response_size: usize, chunk_size: usize) {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /gzip HTTP/1.1\r\n\ GET /gzip HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
chunk_size: chunk_size, chunk_size: chunk_size,
@@ -57,9 +56,9 @@ fn test_gzip(response_size: usize, chunk_size: usize) {
response: response 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())) let res_future = client.get(&format!("http://{}/gzip", server.addr()))
.send() .send()
@@ -75,5 +74,5 @@ fn test_gzip(response_size: usize, chunk_size: usize) {
Ok(()) Ok(())
}); });
core.run(res_future).unwrap(); rt.block_on(res_future).unwrap();
} }

View File

@@ -10,10 +10,10 @@ fn test_response_text() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /text HTTP/1.1\r\n\ GET /text HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -28,11 +28,9 @@ fn test_response_text() {
let url = format!("http://{}/text", server.addr()); let url = format!("http://{}/text", server.addr());
let mut res = reqwest::get(&url).unwrap(); let mut res = reqwest::get(&url).unwrap();
assert_eq!(res.url().as_str(), &url); assert_eq!(res.url().as_str(), &url);
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
assert_eq!(res.headers().get(), assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
Some(&reqwest::header::Server::new("test".to_string()))); assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"5");
assert_eq!(res.headers().get(),
Some(&reqwest::header::ContentLength(5)));
let body = res.text().unwrap(); let body = res.text().unwrap();
assert_eq!(b"Hello", body.as_bytes()); assert_eq!(b"Hello", body.as_bytes());
@@ -43,10 +41,10 @@ fn test_response_non_utf_8_text() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /text HTTP/1.1\r\n\ GET /text HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -62,11 +60,9 @@ fn test_response_non_utf_8_text() {
let url = format!("http://{}/text", server.addr()); let url = format!("http://{}/text", server.addr());
let mut res = reqwest::get(&url).unwrap(); let mut res = reqwest::get(&url).unwrap();
assert_eq!(res.url().as_str(), &url); assert_eq!(res.url().as_str(), &url);
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
assert_eq!(res.headers().get(), assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
Some(&reqwest::header::Server::new("test".to_string()))); assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"4");
assert_eq!(res.headers().get(),
Some(&reqwest::header::ContentLength(4)));
let body = res.text().unwrap(); let body = res.text().unwrap();
assert_eq!("你好", &body); assert_eq!("你好", &body);
@@ -78,10 +74,10 @@ fn test_response_copy_to() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /1 HTTP/1.1\r\n\ GET /1 HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -96,11 +92,9 @@ fn test_response_copy_to() {
let url = format!("http://{}/1", server.addr()); let url = format!("http://{}/1", server.addr());
let mut res = reqwest::get(&url).unwrap(); let mut res = reqwest::get(&url).unwrap();
assert_eq!(res.url().as_str(), &url); assert_eq!(res.url().as_str(), &url);
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
assert_eq!(res.headers().get(), assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
Some(&reqwest::header::Server::new("test".to_string()))); assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"5");
assert_eq!(res.headers().get(),
Some(&reqwest::header::ContentLength(5)));
let mut buf: Vec<u8> = vec![]; let mut buf: Vec<u8> = vec![];
res.copy_to(&mut buf).unwrap(); res.copy_to(&mut buf).unwrap();
@@ -112,10 +106,10 @@ fn test_get() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /1 HTTP/1.1\r\n\ GET /1 HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -130,11 +124,9 @@ fn test_get() {
let mut res = reqwest::get(&url).unwrap(); let mut res = reqwest::get(&url).unwrap();
assert_eq!(res.url().as_str(), &url); assert_eq!(res.url().as_str(), &url);
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
assert_eq!(res.headers().get(), assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
Some(&reqwest::header::Server::new("test".to_string()))); assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"0");
assert_eq!(res.headers().get(),
Some(&reqwest::header::ContentLength(0)));
let mut buf = [0; 1024]; let mut buf = [0; 1024];
let n = res.read(&mut buf).unwrap(); let n = res.read(&mut buf).unwrap();
@@ -146,11 +138,11 @@ fn test_post() {
let server = server! { let server = server! {
request: b"\ request: b"\
POST /2 HTTP/1.1\r\n\ POST /2 HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ content-length: 5\r\n\
Content-Length: 5\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
Hello\ Hello\
", ",
@@ -170,11 +162,9 @@ fn test_post() {
.unwrap(); .unwrap();
assert_eq!(res.url().as_str(), &url); assert_eq!(res.url().as_str(), &url);
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
assert_eq!(res.headers().get(), assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"post");
Some(&reqwest::header::Server::new("post"))); assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"0");
assert_eq!(res.headers().get(),
Some(&reqwest::header::ContentLength(0)));
let mut buf = [0; 1024]; let mut buf = [0; 1024];
let n = res.read(&mut buf).unwrap(); let n = res.read(&mut buf).unwrap();
@@ -188,10 +178,10 @@ fn test_error_for_status_4xx() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /1 HTTP/1.1\r\n\ GET /1 HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -207,7 +197,7 @@ fn test_error_for_status_4xx() {
let err = res.error_for_status().err().unwrap(); let err = res.error_for_status().err().unwrap();
assert!(err.is_client_error()); 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 /// 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! { let server = server! {
request: b"\ request: b"\
GET /1 HTTP/1.1\r\n\ GET /1 HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -236,17 +226,14 @@ fn test_error_for_status_5xx() {
let err = res.error_for_status().err().unwrap(); let err = res.error_for_status().err().unwrap();
assert!(err.is_server_error()); assert!(err.is_server_error());
assert_eq!(err.status(), Some(reqwest::StatusCode::InternalServerError)); assert_eq!(err.status(), Some(reqwest::StatusCode::INTERNAL_SERVER_ERROR));
} }
#[test] #[test]
fn test_default_headers() { fn test_default_headers() {
use reqwest::header; use reqwest::header;
let mut headers = header::Headers::with_capacity(1); let mut headers = header::HeaderMap::with_capacity(1);
let mut cookies = header::Cookie::new(); headers.insert(header::COOKIE, header::HeaderValue::from_static("a=b;c=d"));
cookies.set("a", "b");
cookies.set("c", "d");
headers.set(cookies);
let client = reqwest::Client::builder() let client = reqwest::Client::builder()
.default_headers(headers) .default_headers(headers)
.build().unwrap(); .build().unwrap();
@@ -254,11 +241,11 @@ fn test_default_headers() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /1 HTTP/1.1\r\n\ GET /1 HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ cookie: a=b;c=d\r\n\
Cookie: a=b; c=d\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -273,20 +260,18 @@ fn test_default_headers() {
let res = client.get(&url).send().unwrap(); let res = client.get(&url).send().unwrap();
assert_eq!(res.url().as_str(), &url); assert_eq!(res.url().as_str(), &url);
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
assert_eq!(res.headers().get(), assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
Some(&reqwest::header::Server::new("test"))); assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"0");
assert_eq!(res.headers().get(),
Some(&reqwest::header::ContentLength(0)));
let server = server! { let server = server! {
request: b"\ request: b"\
GET /2 HTTP/1.1\r\n\ GET /2 HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ cookie: a=b;c=d\r\n\
Cookie: a=b; c=d\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -301,18 +286,16 @@ fn test_default_headers() {
let res = client.get(&url).send().unwrap(); let res = client.get(&url).send().unwrap();
assert_eq!(res.url().as_str(), &url); assert_eq!(res.url().as_str(), &url);
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
assert_eq!(res.headers().get(), assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
Some(&reqwest::header::Server::new("test"))); assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"0");
assert_eq!(res.headers().get(),
Some(&reqwest::header::ContentLength(0)));
} }
#[test] #[test]
fn test_override_default_headers() { fn test_override_default_headers() {
use reqwest::header; use reqwest::header;
let mut headers = header::Headers::with_capacity(1); let mut headers = header::HeaderMap::with_capacity(1);
headers.set(header::Authorization("iamatoken".to_string())); headers.insert(header::AUTHORIZATION, header::HeaderValue::from_static("iamatoken"));
let client = reqwest::Client::builder() let client = reqwest::Client::builder()
.default_headers(headers) .default_headers(headers)
.build().unwrap(); .build().unwrap();
@@ -320,11 +303,11 @@ fn test_override_default_headers() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /3 HTTP/1.1\r\n\ GET /3 HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ authorization: secret\r\n\
Authorization: secret\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -336,13 +319,11 @@ fn test_override_default_headers() {
}; };
let url = format!("http://{}/3", server.addr()); 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.url().as_str(), &url);
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
assert_eq!(res.headers().get(), assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
Some(&reqwest::header::Server::new("test"))); assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"0");
assert_eq!(res.headers().get(),
Some(&reqwest::header::ContentLength(0)));
} }

View File

@@ -31,10 +31,10 @@ fn test_gzip_response() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /gzip HTTP/1.1\r\n\ GET /gzip HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
chunk_size: chunk_size, chunk_size: chunk_size,
@@ -54,10 +54,10 @@ fn test_gzip_empty_body() {
let server = server! { let server = server! {
request: b"\ request: b"\
HEAD /gzip HTTP/1.1\r\n\ HEAD /gzip HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -85,10 +85,10 @@ fn test_gzip_invalid_body() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /gzip HTTP/1.1\r\n\ GET /gzip HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -113,10 +113,10 @@ fn test_accept_header_is_not_changed_if_set() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /accept HTTP/1.1\r\n\ GET /accept HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: application/json\r\n\
Accept: application/json\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -130,11 +130,11 @@ fn test_accept_header_is_not_changed_if_set() {
let res = client let res = client
.get(&format!("http://{}/accept", server.addr())) .get(&format!("http://{}/accept", server.addr()))
.header(reqwest::header::Accept::json()) .header(reqwest::header::ACCEPT, reqwest::header::HeaderValue::from_static("application/json"))
.send() .send()
.unwrap(); .unwrap();
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
} }
#[test] #[test]
@@ -142,10 +142,10 @@ fn test_accept_encoding_header_is_not_changed_if_set() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /accept-encoding HTTP/1.1\r\n\ GET /accept-encoding HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: identity\r\n\
Accept-Encoding: identity\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -158,11 +158,9 @@ fn test_accept_encoding_header_is_not_changed_if_set() {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let res = client.get(&format!("http://{}/accept-encoding", server.addr())) let res = client.get(&format!("http://{}/accept-encoding", server.addr()))
.header(reqwest::header::AcceptEncoding( .header(reqwest::header::ACCEPT_ENCODING, reqwest::header::HeaderValue::from_static("identity"))
vec![reqwest::header::qitem(reqwest::header::Encoding::Identity)]
))
.send() .send()
.unwrap(); .unwrap();
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
} }

View File

@@ -21,12 +21,12 @@ fn test_multipart() {
let server = server! { let server = server! {
request: format!("\ request: format!("\
POST /multipart/1 HTTP/1.1\r\n\ POST /multipart/1 HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ content-type: multipart/form-data; boundary={}\r\n\
Content-Type: multipart/form-data; boundary={}\r\n\ content-length: 123\r\n\
Content-Length: 123\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
{}\ {}\
", form.boundary(), expected_body), ", form.boundary(), expected_body),
@@ -47,5 +47,5 @@ fn test_multipart() {
.unwrap(); .unwrap();
assert_eq!(res.url().as_str(), &url); assert_eq!(res.url().as_str(), &url);
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
} }

View File

@@ -8,10 +8,10 @@ fn test_http_proxy() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET http://hyper.rs/prox HTTP/1.1\r\n\ GET http://hyper.rs/prox HTTP/1.1\r\n\
Host: hyper.rs\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: hyper.rs\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -34,7 +34,6 @@ fn test_http_proxy() {
.unwrap(); .unwrap();
assert_eq!(res.url().as_str(), url); assert_eq!(res.url().as_str(), url);
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
assert_eq!(res.headers().get(), assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"proxied");
Some(&reqwest::header::Server::new("proxied")));
} }

View File

@@ -12,10 +12,10 @@ fn test_redirect_301_and_302_and_303_changes_post_to_get() {
let redirect = server! { let redirect = server! {
request: format!("\ request: format!("\
POST /{} HTTP/1.1\r\n\ POST /{} HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", code), ", code),
response: format!("\ response: format!("\
@@ -29,11 +29,11 @@ fn test_redirect_301_and_302_and_303_changes_post_to_get() {
request: format!("\ request: format!("\
GET /dst HTTP/1.1\r\n\ GET /dst HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ referer: http://$HOST/{}\r\n\
Referer: http://$HOST/{}\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", code), ", code),
response: b"\ response: b"\
@@ -50,9 +50,8 @@ fn test_redirect_301_and_302_and_303_changes_post_to_get() {
.send() .send()
.unwrap(); .unwrap();
assert_eq!(res.url().as_str(), dst); assert_eq!(res.url().as_str(), dst);
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
assert_eq!(res.headers().get(), assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test-dst");
Some(&reqwest::header::Server::new("test-dst".to_string())));
} }
} }
@@ -64,10 +63,10 @@ fn test_redirect_307_and_308_tries_to_get_again() {
let redirect = server! { let redirect = server! {
request: format!("\ request: format!("\
GET /{} HTTP/1.1\r\n\ GET /{} HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", code), ", code),
response: format!("\ response: format!("\
@@ -81,11 +80,11 @@ fn test_redirect_307_and_308_tries_to_get_again() {
request: format!("\ request: format!("\
GET /dst HTTP/1.1\r\n\ GET /dst HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ referer: http://$HOST/{}\r\n\
Referer: http://$HOST/{}\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", code), ", code),
response: b"\ response: b"\
@@ -102,9 +101,8 @@ fn test_redirect_307_and_308_tries_to_get_again() {
.send() .send()
.unwrap(); .unwrap();
assert_eq!(res.url().as_str(), dst); assert_eq!(res.url().as_str(), dst);
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
assert_eq!(res.headers().get(), assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test-dst");
Some(&reqwest::header::Server::new("test-dst".to_string())));
} }
} }
@@ -116,11 +114,11 @@ fn test_redirect_307_and_308_tries_to_post_again() {
let redirect = server! { let redirect = server! {
request: format!("\ request: format!("\
POST /{} HTTP/1.1\r\n\ POST /{} HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ content-length: 5\r\n\
Content-Length: 5\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
Hello\ Hello\
", code), ", code),
@@ -135,12 +133,12 @@ fn test_redirect_307_and_308_tries_to_post_again() {
request: format!("\ request: format!("\
POST /dst HTTP/1.1\r\n\ POST /dst HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ content-length: 5\r\n\
Content-Length: 5\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ referer: http://$HOST/{}\r\n\
Referer: http://$HOST/{}\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
Hello\ Hello\
", code), ", code),
@@ -159,9 +157,8 @@ fn test_redirect_307_and_308_tries_to_post_again() {
.send() .send()
.unwrap(); .unwrap();
assert_eq!(res.url().as_str(), dst); assert_eq!(res.url().as_str(), dst);
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
assert_eq!(res.headers().get(), assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test-dst");
Some(&reqwest::header::Server::new("test-dst".to_string())));
} }
} }
@@ -173,11 +170,11 @@ fn test_redirect_307_does_not_try_if_reader_cannot_reset() {
let redirect = server! { let redirect = server! {
request: format!("\ request: format!("\
POST /{} HTTP/1.1\r\n\ POST /{} HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
Transfer-Encoding: chunked\r\n\ transfer-encoding: chunked\r\n\
\r\n\ \r\n\
5\r\n\ 5\r\n\
Hello\r\n\ Hello\r\n\
@@ -200,7 +197,7 @@ fn test_redirect_307_does_not_try_if_reader_cannot_reset() {
.send() .send()
.unwrap(); .unwrap();
assert_eq!(res.url().as_str(), url); 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! { let end_server = server! {
request: b"\ request: b"\
GET /otherhost HTTP/1.1\r\n\ GET /otherhost HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -228,11 +225,11 @@ fn test_redirect_removes_sensitive_headers() {
let mid_server = server! { let mid_server = server! {
request: b"\ request: b"\
GET /sensitive HTTP/1.1\r\n\ GET /sensitive HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ cookie: foo=bar\r\n\
Cookie: foo=bar\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: format!("\ response: format!("\
@@ -244,14 +241,12 @@ fn test_redirect_removes_sensitive_headers() {
", end_server.addr()) ", end_server.addr())
}; };
let mut cookie = reqwest::header::Cookie::new();
cookie.set("foo", "bar");
reqwest::Client::builder() reqwest::Client::builder()
.referer(false) .referer(false)
.build() .build()
.unwrap() .unwrap()
.get(&format!("http://{}/sensitive", mid_server.addr())) .get(&format!("http://{}/sensitive", mid_server.addr()))
.header(cookie) .header(reqwest::header::COOKIE, reqwest::header::HeaderValue::from_static("foo=bar"))
.send() .send()
.unwrap(); .unwrap();
} }
@@ -261,10 +256,10 @@ fn test_redirect_policy_can_return_errors() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /loop HTTP/1.1\r\n\ GET /loop HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -285,10 +280,10 @@ fn test_redirect_policy_can_stop_redirects_without_an_error() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /no-redirect HTTP/1.1\r\n\ GET /no-redirect HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -311,9 +306,8 @@ fn test_redirect_policy_can_stop_redirects_without_an_error() {
.unwrap(); .unwrap();
assert_eq!(res.url().as_str(), url); assert_eq!(res.url().as_str(), url);
assert_eq!(res.status(), reqwest::StatusCode::Found); assert_eq!(res.status(), reqwest::StatusCode::FOUND);
assert_eq!(res.headers().get(), assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test-dont");
Some(&reqwest::header::Server::new("test-dont".to_string())));
} }
#[test] #[test]
@@ -321,10 +315,10 @@ fn test_referer_is_not_set_if_disabled() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /no-refer HTTP/1.1\r\n\ GET /no-refer HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -338,10 +332,10 @@ fn test_referer_is_not_set_if_disabled() {
request: b"\ request: b"\
GET /dst HTTP/1.1\r\n\ GET /dst HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\

View File

@@ -11,11 +11,11 @@ fn test_write_timeout() {
let server = server! { let server = server! {
request: b"\ request: b"\
POST /write-timeout HTTP/1.1\r\n\ POST /write-timeout HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
Content-Length: 5\r\n\ accept: */*\r\n\
User-Agent: $USERAGENT\r\n\ content-length: 5\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
Hello\ Hello\
", ",
@@ -34,7 +34,7 @@ fn test_write_timeout() {
.build() .build()
.unwrap() .unwrap()
.post(&url) .post(&url)
.header(reqwest::header::ContentLength(5)) .header(reqwest::header::CONTENT_LENGTH, reqwest::header::HeaderValue::from_static("5"))
.body(reqwest::Body::new(&b"Hello"[..])) .body(reqwest::Body::new(&b"Hello"[..]))
.send() .send()
.unwrap_err(); .unwrap_err();
@@ -49,10 +49,10 @@ fn test_response_timeout() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /response-timeout HTTP/1.1\r\n\ GET /response-timeout HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -80,10 +80,10 @@ fn test_read_timeout() {
let server = server! { let server = server! {
request: b"\ request: b"\
GET /read-timeout HTTP/1.1\r\n\ GET /read-timeout HTTP/1.1\r\n\
Host: $HOST\r\n\ user-agent: $USERAGENT\r\n\
User-Agent: $USERAGENT\r\n\ accept: */*\r\n\
Accept: */*\r\n\ accept-encoding: gzip\r\n\
Accept-Encoding: gzip\r\n\ host: $HOST\r\n\
\r\n\ \r\n\
", ",
response: b"\ response: b"\
@@ -105,9 +105,8 @@ fn test_read_timeout() {
.unwrap(); .unwrap();
assert_eq!(res.url().as_str(), &url); assert_eq!(res.url().as_str(), &url);
assert_eq!(res.status(), reqwest::StatusCode::Ok); assert_eq!(res.status(), reqwest::StatusCode::OK);
assert_eq!(res.headers().get(), assert_eq!(res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(), &"5");
Some(&reqwest::header::ContentLength(5)));
let mut buf = [0; 1024]; let mut buf = [0; 1024];
let err = res.read(&mut buf).unwrap_err(); let err = res.read(&mut buf).unwrap_err();