Skip to content

Commit

Permalink
Move code related to client to its own module
Browse files Browse the repository at this point in the history
  • Loading branch information
threema-donat committed Aug 5, 2024
1 parent 9d09d5b commit 5ecd79c
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 132 deletions.
125 changes: 3 additions & 122 deletions src/authenticator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use crate::application_default_credentials::{
};
use crate::authenticator_delegate::{DeviceFlowDelegate, InstalledFlowDelegate};
use crate::authorized_user::{AuthorizedUserFlow, AuthorizedUserSecret};
use crate::client::{HttpClient, LegacyClient};
#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
use crate::client::DefaultHyperClient;
use crate::client::{HttpClient, HyperClientBuilder};
use crate::device::DeviceFlow;
use crate::error::Error;
use crate::external_account::{ExternalAccountFlow, ExternalAccountSecret};
Expand All @@ -17,10 +19,6 @@ use crate::service_account::{self, ServiceAccountFlow, ServiceAccountFlowOpts, S
use crate::storage::{self, Storage, TokenStorage};
use crate::types::{AccessToken, ApplicationSecret, TokenInfo};
use private::AuthFlow;
#[cfg(all(feature = "aws-lc-rs", feature = "hyper-rustls", not(feature = "ring")))]
use rustls::crypto::aws_lc_rs::default_provider as default_crypto_provider;
#[cfg(all(feature = "ring", feature = "hyper-rustls"))]
use rustls::crypto::ring::default_provider as default_crypto_provider;

use crate::access_token::AccessTokenFlow;

Expand Down Expand Up @@ -933,18 +931,6 @@ mod private {
}
}

/// A trait implemented for any hyper_util::client::legacy::Client as well as the DefaultHyperClient.
pub trait HyperClientBuilder {
/// The hyper connector that the resulting hyper client will use.
type Connector: Connect + Clone + Send + Sync + 'static;

/// Sets duration after which a request times out
fn with_timeout(self, timeout: Duration) -> Self;

/// Create a hyper::Client
fn build_hyper_client(self) -> Result<HttpClient<Self::Connector>, Error>;
}

#[cfg(feature = "hyper-rustls")]
#[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))]
/// Default authenticator type
Expand All @@ -957,111 +943,6 @@ pub type DefaultAuthenticator =
pub type DefaultAuthenticator =
Authenticator<hyper_tls::HttpsConnector<hyper_util::client::legacy::connect::HttpConnector>>;

/// The builder value used when the default hyper client should be used.
#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))]
#[derive(Default)]
pub struct DefaultHyperClient {
timeout: Option<Duration>,
}

/// Intended for using an existing hyper client with `yup-oauth2`. Instantiate
/// with [`CustomHyperClient::from`]
pub struct CustomHyperClient<C>
where
C: Connect + Clone + Send + Sync + 'static,
{
client: HttpClient<C>,
timeout: Option<Duration>,
}

impl<C> From<LegacyClient<C>> for CustomHyperClient<C>
where
C: Connect + Clone + Send + Sync + 'static,
{
fn from(client: LegacyClient<C>) -> Self {
Self {
client: HttpClient::new(client, None),
timeout: None,
}
}
}

impl<C> HyperClientBuilder for CustomHyperClient<C>
where
C: Connect + Clone + Send + Sync + 'static,
{
type Connector = C;

fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}

fn build_hyper_client(self) -> Result<HttpClient<Self::Connector>, Error> {
Ok(self.client)
}
}

#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
impl DefaultHyperClient {
/// Set the duration after which a request times out
pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
}

#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))]
impl HyperClientBuilder for DefaultHyperClient {
#[cfg(feature = "hyper-rustls")]
type Connector =
hyper_rustls::HttpsConnector<hyper_util::client::legacy::connect::HttpConnector>;
#[cfg(all(not(feature = "hyper-rustls"), feature = "hyper-tls"))]
type Connector = hyper_tls::HttpsConnector<hyper_util::client::legacy::connect::HttpConnector>;

fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}

fn build_hyper_client(self) -> Result<HttpClient<Self::Connector>, Error> {
#[cfg(feature = "hyper-rustls")]
let connector = hyper_rustls::HttpsConnectorBuilder::new()
.with_provider_and_native_roots(default_crypto_provider())?
.https_or_http()
.enable_http1()
.enable_http2()
.build();
#[cfg(all(not(feature = "hyper-rustls"), feature = "hyper-tls"))]
let connector = hyper_tls::HttpsConnector::new();

Ok(HttpClient::new(
hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new())
.pool_max_idle_per_host(0)
.build::<_, String>(connector),
self.timeout,
))
}
}

impl<C> HyperClientBuilder for HttpClient<C>
where
C: Connect + Clone + Send + Sync + 'static,
{
type Connector = C;

fn with_timeout(mut self, timeout: Duration) -> Self {
self.set_timeout(timeout);
self
}

fn build_hyper_client(self) -> Result<HttpClient<Self::Connector>, Error> {
Ok(self)
}
}

/// How should the acquired tokens be stored?
enum StorageType {
/// Store tokens in memory (and always log in again to acquire a new token on startup)
Expand Down
130 changes: 127 additions & 3 deletions src/client.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
//! Module containing the HTTP client used for sending requests
use std::time::Duration;

use futures::TryFutureExt;
use http::Uri;
use hyper_util::client::legacy::{connect::Connect, Error as LegacyHyperError};
use thiserror::Error as ThisError;
#[cfg(all(feature = "aws-lc-rs", feature = "hyper-rustls", not(feature = "ring")))]
use rustls::crypto::aws_lc_rs::default_provider as default_crypto_provider;
#[cfg(all(feature = "ring", feature = "hyper-rustls"))]
use rustls::crypto::ring::default_provider as default_crypto_provider;

use crate::Error;

type HyperResponse = http::Response<hyper::body::Incoming>;
pub(crate) type LegacyClient<C> = hyper_util::client::legacy::Client<C, String>;
Expand All @@ -19,6 +26,18 @@ pub enum SendError {
Hyper(#[source] LegacyHyperError),
}

/// A trait implemented for any hyper_util::client::legacy::Client as well as the DefaultHyperClient.
pub trait HyperClientBuilder {
/// The hyper connector that the resulting hyper client will use.
type Connector: Connect + Clone + Send + Sync + 'static;

/// Sets duration after which a request times out
fn with_timeout(self, timeout: Duration) -> Self;

/// Create a hyper::Client
fn build_hyper_client(self) -> Result<HttpClient<Self::Connector>, Error>;
}

/// Client that can be configured that a request will timeout after a specified
/// duration.
#[derive(Clone)]
Expand All @@ -34,14 +53,14 @@ impl<C> HttpClient<C>
where
C: Connect + Clone + Send + Sync + 'static,
{
pub(super) fn new(hyper_client: LegacyClient<C>, timeout: Option<Duration>) -> Self {
pub(crate) fn new(hyper_client: LegacyClient<C>, timeout: Option<Duration>) -> Self {
Self {
client: hyper_client,
timeout,
}
}

pub(super) fn set_timeout(&mut self, timeout: Duration) {
pub(crate) fn set_timeout(&mut self, timeout: Duration) {
self.timeout = Some(timeout);
}

Expand All @@ -52,6 +71,22 @@ where
}
}

impl<C> HyperClientBuilder for HttpClient<C>
where
C: Connect + Clone + Send + Sync + 'static,
{
type Connector = C;

fn with_timeout(mut self, timeout: Duration) -> Self {
self.set_timeout(timeout);
self
}

fn build_hyper_client(self) -> Result<HttpClient<Self::Connector>, Error> {
Ok(self)
}
}

impl<C> SendRequest for HttpClient<C>
where
C: Connect + Clone + Send + Sync + 'static,
Expand All @@ -70,6 +105,95 @@ where
}
}

pub(super) trait SendRequest {
pub(crate) trait SendRequest {
async fn request(&self, payload: http::Request<String>) -> Result<HyperResponse, SendError>;
}

/// The builder value used when the default hyper client should be used.
#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))]
#[derive(Default)]
pub struct DefaultHyperClient {
timeout: Option<Duration>,
}

#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
impl DefaultHyperClient {
/// Set the duration after which a request times out
pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
}

#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))))]
impl HyperClientBuilder for DefaultHyperClient {
#[cfg(feature = "hyper-rustls")]
type Connector =
hyper_rustls::HttpsConnector<hyper_util::client::legacy::connect::HttpConnector>;
#[cfg(all(not(feature = "hyper-rustls"), feature = "hyper-tls"))]
type Connector = hyper_tls::HttpsConnector<hyper_util::client::legacy::connect::HttpConnector>;

fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}

fn build_hyper_client(self) -> Result<HttpClient<Self::Connector>, Error> {
#[cfg(feature = "hyper-rustls")]
let connector = hyper_rustls::HttpsConnectorBuilder::new()
.with_provider_and_native_roots(default_crypto_provider())?
.https_or_http()
.enable_http1()
.enable_http2()
.build();
#[cfg(all(not(feature = "hyper-rustls"), feature = "hyper-tls"))]
let connector = hyper_tls::HttpsConnector::new();

Ok(HttpClient::new(
hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new())
.pool_max_idle_per_host(0)
.build::<_, String>(connector),
self.timeout,
))
}
}

/// Intended for using an existing hyper client with `yup-oauth2`. Instantiate
/// with [`CustomHyperClient::from`]
pub struct CustomHyperClient<C>
where
C: Connect + Clone + Send + Sync + 'static,
{
client: HttpClient<C>,
timeout: Option<Duration>,
}

impl<C> From<LegacyClient<C>> for CustomHyperClient<C>
where
C: Connect + Clone + Send + Sync + 'static,
{
fn from(client: LegacyClient<C>) -> Self {
Self {
client: HttpClient::new(client, None),
timeout: None,
}
}
}

impl<C> HyperClientBuilder for CustomHyperClient<C>
where
C: Connect + Clone + Send + Sync + 'static,
{
type Connector = C;

fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}

fn build_hyper_client(self) -> Result<HttpClient<Self::Connector>, Error> {
Ok(self.client)
}
}
7 changes: 4 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ mod application_default_credentials;
pub mod authenticator;
pub mod authenticator_delegate;
pub mod authorized_user;
mod client;
pub mod client;
mod device;
pub mod error;
pub mod external_account;
Expand Down Expand Up @@ -107,12 +107,13 @@ pub use crate::authenticator::ServiceAccountAuthenticator;
#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
pub use crate::authenticator::AccessTokenAuthenticator;

pub use crate::client::{HttpClient, CustomHyperClient};
#[cfg(any(feature = "hyper-rustls", feature = "hyper-tls"))]
pub use crate::client::HttpClient;
pub use crate::client::DefaultHyperClient;

#[doc(inline)]
pub use crate::authenticator::{
ApplicationDefaultCredentialsAuthenticator, AuthorizedUserAuthenticator, CustomHyperClient,
ApplicationDefaultCredentialsAuthenticator, AuthorizedUserAuthenticator,
DeviceFlowAuthenticator, ExternalAccountAuthenticator, InstalledFlowAuthenticator,
ServiceAccountImpersonationAuthenticator,
};
Expand Down
9 changes: 5 additions & 4 deletions tests/tests.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use yup_oauth2::{
authenticator::{DefaultAuthenticator, DefaultHyperClient, HyperClientBuilder},
authenticator::DefaultAuthenticator,
authenticator_delegate::{DeviceAuthResponse, DeviceFlowDelegate, InstalledFlowDelegate},
client::HyperClientBuilder,
error::SendError,
AccessTokenAuthenticator, ApplicationDefaultCredentialsAuthenticator,
ApplicationDefaultCredentialsFlowOpts, ApplicationSecret, DeviceFlowAuthenticator, HttpClient,
InstalledFlowAuthenticator, InstalledFlowReturnMethod, ServiceAccountAuthenticator,
ServiceAccountKey,
ApplicationDefaultCredentialsFlowOpts, ApplicationSecret, DefaultHyperClient,
DeviceFlowAuthenticator, HttpClient, InstalledFlowAuthenticator, InstalledFlowReturnMethod,
ServiceAccountAuthenticator, ServiceAccountKey,
};

use std::path::PathBuf;
Expand Down

0 comments on commit 5ecd79c

Please sign in to comment.