1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//!Describes client configuration

use std::io::Write;
use core::time;

use crate::utils;
use crate::header;

///Default timer, which is used by [DefaultCfg](struct.DefaultCfg.html)
pub type DefaultTimer = async_timer::oneshot::Timer;
#[cfg(feature = "rustls-on")]
///Default connector, which is used by [DefaultCfg](struct.DefaultCfg.html)
pub type DefaultConnector = crate::connector::rustls::HttpsConnector;
#[cfg(not(feature = "rustls-on"))]
///Default connector, which is used by [DefaultCfg](struct.DefaultCfg.html)
pub type DefaultConnector = crate::connector::HttpConnector;

///Generic config trait.
///
///Each method describes single aspect of configuration
///and provided with sane defaults
pub trait Config {
    ///Connector type.
    type Connector: hyper::service::Service<hyper::Uri> + Default + Clone + Send + Sync;
    ///Timer type.
    type Timer: async_timer::oneshot::Oneshot;

    #[inline]
    ///Specifies whether to automatically request compressed response.
    ///
    ///Defaults to true.
    fn decompress() -> bool {
        true
    }

    #[inline]
    ///Specifies request timeout.
    ///
    ///Default is 30 seconds
    ///
    ///Zero duration means infinite
    fn timeout() -> time::Duration {
        time::Duration::from_secs(30)
    }

    ///Specifies how to set user agent
    ///
    ///By default it set's `Yukikaze/<lib version>`, if agent is not present
    fn default_user_agent(request: &mut super::request::Request) {
        if !request.headers().contains_key(header::USER_AGENT) {
            request.headers_mut().insert(header::USER_AGENT, header::HeaderValue::from_static(concat!("Yukikaze/", env!("CARGO_PKG_VERSION"))));
        }
    }

    #[inline]
    ///Allows to sets default headers before request
    ///is sent out
    ///
    ///It is called as soon as request is being sent out,
    ///but before `Accept-Encoding` is set.
    ///
    ///By default it sets following, if not present:
    ///
    ///- Set default user agent;
    ///- `HOST` header with host, and optionally port, taken from URI;
    fn default_headers(request: &mut super::request::Request) {
        Self::default_user_agent(request);

        if !request.headers().contains_key(header::HOST) {
            let host = request.uri().host().and_then(|host| match request.uri().port().map(|port| port.as_u16()) {
                None | Some(80) | Some(443) => header::HeaderValue::from_str(host).ok(),
                Some(port) => {
                    let mut buffer = utils::BytesWriter::with_capacity(host.len() + 5);
                    let _ = write!(&mut buffer, "{}:{}", host, port);

                    http::header::HeaderValue::from_maybe_shared(buffer.freeze()).ok()
                },
            });

            if let Some(host) = host {
                request.headers_mut().insert(header::HOST, host);
            }
        }
    }

    #[inline]
    ///Returns max number of redirects
    ///
    ///By default it is 8.
    fn max_redirect_num() -> usize {
        8
    }

    #[inline]
    ///Allows to hook hyper's Client configuration.
    ///
    ///By default it uses hyper's defaults
    fn config_hyper(builder: &mut hyper::client::Builder) -> &mut hyper::client::Builder {
        builder
    }
}

///Default configuration.
///
///Uses default [Config](trait.Config.html) impl.
///
///Connector:
///
///- When `rustls` enabled uses `yukikaze::connector::rustls::HttpsConnector` as default
///
///- Otherwise uses `yukikaze::connector::HttpConnector`
pub struct DefaultCfg;

impl Config for DefaultCfg {
    type Connector = DefaultConnector;
    type Timer = DefaultTimer;
}