diff --git a/Cargo.toml b/Cargo.toml index ad5ce8e..7f96c2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,8 +16,6 @@ exclude = [ base64 = "0.10" error-chain = { version = "0.12", default-features = false } futures = "0.1" -hyper = "0.12" -hyper-rustls = "0.15" http = "0.1" libflate = "0.1" log = "0.4" diff --git a/src/errors.rs b/src/errors.rs index cb9f987..c298174 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -2,7 +2,6 @@ use base64; use http; -use hyper; use regex; use reqwest; use serde_json; @@ -11,9 +10,9 @@ use std::{io, string}; error_chain! { foreign_links { Base64Decode(base64::DecodeError); - HeaderInvalid(hyper::header::InvalidHeaderValue); - HeaderParse(hyper::header::ToStrError); - Hyper(hyper::Error); + HeaderInvalid(http::header::InvalidHeaderValue); + HeaderParse(http::header::ToStrError); + Hyper(http::Error); Io(io::Error); Json(serde_json::Error); Regex(regex::Error); diff --git a/src/lib.rs b/src/lib.rs index 5fc124f..6098bc2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,8 +38,6 @@ extern crate base64; extern crate futures; extern crate http; -extern crate hyper; -extern crate hyper_rustls; extern crate mime; extern crate serde; extern crate serde_json; diff --git a/src/v2/auth.rs b/src/v2/auth.rs index 0a77e34..2cc7871 100644 --- a/src/v2/auth.rs +++ b/src/v2/auth.rs @@ -1,6 +1,5 @@ -use base64; use futures::{future, prelude::*}; -use hyper::header; +use reqwest::{StatusCode, Url}; use v2::*; /// Convenience alias for future `TokenAuth` result. @@ -85,7 +84,7 @@ impl Client { /// /// On success, the returned token will be valid for all requested scopes. pub fn login(&self, scopes: &[&str]) -> FutureTokenAuth { - let subclient = self.hclient.clone(); + let subclient = self.clone(); let creds = self.credentials.clone(); let scope = scopes .iter() @@ -95,32 +94,30 @@ impl Client { .and_then(move |token_ep| { let auth_ep = token_ep + scope.as_str(); trace!("Token endpoint: {}", auth_ep); - hyper::Uri::from_str(auth_ep.as_str()).map_err(|e| e.into()) + + reqwest::Url::parse(&auth_ep).map_err(|e| { + Error::from(format!( + "failed to parse url from string '{}': {}", + auth_ep, e + )) + }) }) .and_then(move |u| { - let mut auth_req = hyper::Request::default(); - *auth_req.method_mut() = hyper::Method::GET; - *auth_req.uri_mut() = u; - if let Some(c) = creds { - let plain = format!("{}:{}", c.0, c.1); - let basic = format!("Basic {}", base64::encode(&plain)); - if let Ok(basic_header) = header::HeaderValue::from_str(&basic) { - auth_req - .headers_mut() - .append(header::AUTHORIZATION, basic_header); + let auth_req = { + let auth_req = subclient.build_reqwest(reqwest::async::Client::new().get(u)); + if let Some(creds) = creds { + auth_req.basic_auth(creds.0, Some(creds.1)) } else { - let msg = format!("could not parse HeaderValue from '{}'", basic); - error!("{}", msg); - // TODO: return an error. seems difficult to match the error type for the whole closure - }; + auth_req + } }; - subclient.request(auth_req).map_err(|e| e.into()) + auth_req.send().map_err(|e| e.into()) }) .and_then(|r| { let status = r.status(); trace!("Got status {}", status); match status { - hyper::StatusCode::OK => Ok(r), + StatusCode::OK => Ok(r), _ => Err(format!("login: wrong HTTP status '{}'", status).into()), } }) @@ -130,7 +127,7 @@ impl Client { .map_err(|e| format!("login: failed to fetch the whole body: {}", e).into()) }) .and_then(|body| { - let s = String::from_utf8(body.into_bytes().to_vec())?; + let s = String::from_utf8(body.to_vec())?; serde_json::from_slice(s.as_bytes()).map_err(|e| e.into()) }) .inspect(|_| { @@ -143,7 +140,7 @@ impl Client { pub fn is_auth(&self, token: Option<&str>) -> FutureBool { let url = { let ep = format!("{}/v2/", self.base_url.clone(),); - match reqwest::Url::parse(&ep) { + match Url::parse(&ep) { Ok(url) => url, Err(e) => { return Box::new(future::err::<_, _>(Error::from(format!( diff --git a/src/v2/catalog.rs b/src/v2/catalog.rs index d82dd48..fdd9b17 100644 --- a/src/v2/catalog.rs +++ b/src/v2/catalog.rs @@ -1,6 +1,6 @@ use errors::{Error, Result}; -use futures::{self, Future, Stream}; -use hyper; +use futures::{self, stream, Future, Stream}; +use reqwest::StatusCode; use serde_json; use std::str::FromStr; use v2; @@ -21,33 +21,28 @@ impl v2::Client { } else { "".to_string() }; - let ep = format!("{}/v2/_catalog{}", self.base_url, suffix); - match hyper::Uri::from_str(ep.as_str()) { + let ep = format!("{}/v2/_catalog{}", self.base_url.clone(), suffix); + match reqwest::Url::parse(&ep) { Ok(url) => url, Err(e) => { - let msg = format!("new_request failed: {}", e); - error!("{}", msg); - return Box::new(futures::stream::once::<_, Error>(Err(Error::from(msg)))); + return Box::new(stream::once::<_, _>(Err(Error::from(format!( + "failed to parse url from string '{}': {}", + ep, e + ))))); } } }; - let req = match self.new_request(hyper::Method::GET, url) { - Ok(r) => r, - Err(e) => { - let msg = format!("new_request failed: {}", e); - error!("{}", msg); - return Box::new(futures::stream::once::<_, Error>(Err(Error::from(msg)))); - } - }; - let freq = self.hclient.request(req); - let fres = freq + let req = self.build_reqwest(reqwest::async::Client::new().get(url)); + + let fres = req + .send() .from_err() .and_then(|r| { let status = r.status(); trace!("Got status: {:?}", status); match status { - hyper::StatusCode::OK => Ok(r), + StatusCode::OK => Ok(r), _ => Err(format!("get_catalog: wrong HTTP status '{}'", status).into()), } }) @@ -57,7 +52,7 @@ impl v2::Client { }) }) .and_then(|body| -> Result { - serde_json::from_slice(&body.into_bytes()).map_err(|e| e.into()) + serde_json::from_slice(&body).map_err(|e| e.into()) }) .map(|cat| futures::stream::iter_ok(cat.repositories.into_iter())) .flatten_stream(); diff --git a/src/v2/config.rs b/src/v2/config.rs index de27e88..0161ca7 100644 --- a/src/v2/config.rs +++ b/src/v2/config.rs @@ -1,10 +1,8 @@ -use hyper::client; use v2::*; /// Configuration for a `Client`. #[derive(Debug)] pub struct Config { - config: client::Client, hyper::Body>, index: String, insecure_registry: bool, user_agent: Option, @@ -15,10 +13,7 @@ pub struct Config { impl Config { /// Initialize `Config` with default values. pub fn default() -> Self { - let dns_threads = 4; Self { - config: hyper::client::Client::builder() - .build(hyper_rustls::HttpsConnector::new(dns_threads)), index: "registry-1.docker.io".into(), insecure_registry: false, user_agent: Some(::USER_AGENT.to_owned()), @@ -89,7 +84,6 @@ impl Config { let c = Client { base_url: base, credentials: creds, - hclient: self.config, index: self.index, user_agent: self.user_agent, token: None, diff --git a/src/v2/mod.rs b/src/v2/mod.rs index 166ab19..06af5bc 100644 --- a/src/v2/mod.rs +++ b/src/v2/mod.rs @@ -31,8 +31,7 @@ use super::errors::*; use futures::prelude::*; -use hyper::{self, client, header}; -use hyper_rustls; +use reqwest::StatusCode; use serde_json; use std::str::FromStr; @@ -59,7 +58,6 @@ pub use self::blobs::FutureBlob; pub struct Client { base_url: String, credentials: Option<(String, String)>, - hclient: client::Client>, index: String, user_agent: Option, token: Option, @@ -79,30 +77,6 @@ impl Client { Config::default() } - fn new_request( - &self, - method: hyper::Method, - url: hyper::Uri, - ) -> Result> { - let mut req = hyper::Request::default(); - *req.method_mut() = method; - *req.uri_mut() = url; - req.headers_mut() - .append(header::HOST, header::HeaderValue::from_str(&self.index)?); - if let Some(ref t) = self.token { - let bearer = format!("Bearer {}", t); - req.headers_mut().append( - header::AUTHORIZATION, - header::HeaderValue::from_str(&bearer)?, - ); - }; - if let Some(ref ua) = self.user_agent { - req.headers_mut() - .append(header::USER_AGENT, header::HeaderValue::from_str(ua)?); - }; - Ok(req) - } - /// Ensure remote registry supports v2 API. pub fn ensure_v2_registry(self) -> impl Future { self.is_v2_supported() @@ -136,8 +110,8 @@ impl Client { // https://docs.docker.com/registry/spec/api/#api-version-check get_v2 .and_then(move |r| match (r.status(), r.headers().get(api_header)) { - (hyper::StatusCode::OK, Some(x)) => Ok(x == api_version), - (hyper::StatusCode::UNAUTHORIZED, Some(x)) => Ok(x == api_version), + (StatusCode::OK, Some(x)) => Ok(x == api_version), + (StatusCode::UNAUTHORIZED, Some(x)) => Ok(x == api_version), (s, v) => { trace!("Got unexpected status {}, header version {:?}", s, v); Ok(false)