async fn exchange(&self, query: &Message) -> Result<Message, crate::Error> {
        if query.questions.len() != 1 {
            return Err(Error::InvalidArgument(
                "expected exactly one question must be provided".to_string(),
            ));
        }

        // Create a Alpn client, so our connection will upgrade to HTTP/2.
        // TODO Move the client into the struct/new()
        // TODO Change the Connector Connect method to allow us to override the DNS
        // resolution in the connector!
        let alpn = AlpnConnector::new();

        let client = HyperClient::builder()
            .pool_idle_timeout(Duration::from_secs(30))
            .http2_only(true)
            .build::<_, hyper::Body>(alpn);

        let question = &query.questions[0];

        let mut url = self.servers[0].clone(); // TODO Support more than one server
        url.query_pairs_mut().append_pair("name", &question.name);
        url.query_pairs_mut()
            .append_pair("type", &question.r#type.to_string());

        url.query_pairs_mut()
            .append_pair("cd", &query.cd.to_string());
        url.query_pairs_mut()
            .append_pair("ct", CONTENT_TYPE_APPLICATION_DNS_JSON);

        if let Some(extension) = &query.extension {
            url.query_pairs_mut()
                .append_pair("do", &extension.dnssec_ok.to_string());
        }

        // TODO Support the following
        // url.query_pairs_mut().append_pair("edns_client_subnet", );
        // url.query_pairs_mut().append_pair("random_padding", );

        // We have to do this wierd as_str().parse() thing because the
        // http::Uri doesn't provide a way to easily mutate or construct it.
        let uri: hyper::Uri = url.as_str().parse()?;

        let req = Request::builder()
            .method(Method::GET)
            .uri(uri)
            .header(ACCEPT, CONTENT_TYPE_APPLICATION_DNS_JSON)
            .body(Body::empty())?;

        let stats = StatsBuilder::start(0);
        let resp = client.request(req).await?;

        if let Some(content_type) = resp.headers().get(CONTENT_TYPE) {
            if !content_type_equal(content_type, CONTENT_TYPE_APPLICATION_DNS_JSON)
                && !content_type_equal(content_type, CONTENT_TYPE_APPLICATION_X_JAVASCRIPT)
            {
                bail!(
                    InvalidData,
                    "recevied invalid content-type: {:?} expected {} or {}",
                    content_type,
                    CONTENT_TYPE_APPLICATION_DNS_JSON,
                    CONTENT_TYPE_APPLICATION_X_JAVASCRIPT,
                );
            }
        }

        if resp.status().is_success() {
            // Get connection information (if available)
            let remote_addr = match resp.extensions().get::<HttpInfo>() {
                Some(http_info) => http_info.remote_addr(),

                // TODO Maybe remote_addr should be optional?
                None => SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0), // Dummy address
            };

            // Read the full body
            let body = hyper::body::to_bytes(resp.into_body()).await?;

            println!("{:?}", body);

            let m: MessageJson = serde_json::from_slice(&body).map_err(ParseError::JsonError)?;
            let mut m: Message = m.try_into()?;
            m.stats = Some(stats.end(remote_addr, body.len()));

            return Ok(m);
        }

        // TODO Retry on 500s. If this is a 4xx we should not retry. Should we follow 3xx?
        bail!(
            InvalidInput,
            "recevied unexpected HTTP status code: {:}",
            resp.status()
        );
    }
/// Sends the [`Message`] to the `server` via HTTP and returns the result.
// TODO Decide if this should be async or not.
// Can return ::std::io::Error
Sends the [`Message`] to the `server` via HTTP and returns the result.
TODO Decide if this should be async or not.
Sends the [ ` Message ` ] to the ` server ` via HTTP and returns the result . TODO Decide if this should be async or not .
async fn exchange(&self, query: &Message) -> Result<Message, crate::Error> {
        if query.questions.len() != 1 {
            return Err(Error::InvalidArgument(
                "expected exactly one question must be provided".to_string(),
            ));
        }
        // Create a Alpn client, so our connection will upgrade to HTTP/2.
        // TODO Move the client into the struct/new()
        // TODO Change the Connector Connect method to allow us to override the DNS
        // resolution in the connector!
        let alpn = AlpnConnector::new();
        let client = HyperClient::builder()
            .pool_idle_timeout(Duration::from_secs(30))
            .http2_only(true)
            .build::<_, hyper::Body>(alpn);
        let question = &query.questions[0];
        let mut url = self.servers[0].clone(); // TODO Support more than one server
        url.query_pairs_mut().append_pair("name", &question.name);
        url.query_pairs_mut()
            .append_pair("type", &question.r#type.to_string());
        url.query_pairs_mut()
            .append_pair("cd", &query.cd.to_string());
        url.query_pairs_mut()
            .append_pair("ct", CONTENT_TYPE_APPLICATION_DNS_JSON);
        if let Some(extension) = &query.extension {
            url.query_pairs_mut()
                .append_pair("do", &extension.dnssec_ok.to_string());
        }
        // TODO Support the following
        // url.query_pairs_mut().append_pair("edns_client_subnet", );
        // url.query_pairs_mut().append_pair("random_padding", );
        // We have to do this wierd as_str().parse() thing because the
        // http::Uri doesn't provide a way to easily mutate or construct it.
        let uri: hyper::Uri = url.as_str().parse()?;
        let req = Request::builder()
            .method(Method::GET)
            .uri(uri)
            .header(ACCEPT, CONTENT_TYPE_APPLICATION_DNS_JSON)
            .body(Body::empty())?;
        let stats = StatsBuilder::start(0);
        let resp = client.request(req).await?;
        if let Some(content_type) = resp.headers().get(CONTENT_TYPE) {
            if !content_type_equal(content_type, CONTENT_TYPE_APPLICATION_DNS_JSON)
                && !content_type_equal(content_type, CONTENT_TYPE_APPLICATION_X_JAVASCRIPT)
            {
                bail!(
                    InvalidData,
                    "recevied invalid content-type: {:?} expected {} or {}",
                    content_type,
                    CONTENT_TYPE_APPLICATION_DNS_JSON,
                    CONTENT_TYPE_APPLICATION_X_JAVASCRIPT,
                );
            }
        }
        if resp.status().is_success() {
            // Get connection information (if available)
            let remote_addr = match resp.extensions().get::<HttpInfo>() {
                Some(http_info) => http_info.remote_addr(),
                // TODO Maybe remote_addr should be optional?
                None => SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0), // Dummy address
            };
            // Read the full body
            let body = hyper::body::to_bytes(resp.into_body()).await?;
            println!("{:?}", body);
            let m: MessageJson = serde_json::from_slice(&body).map_err(ParseError::JsonError)?;
            let mut m: Message = m.try_into()?;
            m.stats = Some(stats.end(remote_addr, body.len()));
            return Ok(m);
        }
        // TODO Retry on 500s. If this is a 4xx we should not retry. Should we follow 3xx?
        bail!(
            InvalidInput,
            "recevied unexpected HTTP status code: {:}",
            resp.status()
        );
    }
async fn exchange ( & self , query : & Message ) -> Result < Message , crate :: Error > { if query . questions . len ( ) != 1 { return Err ( Error :: InvalidArgument ( " " . to_string ( ) , ) ) ; } // Create a Alpn client, so our connection will upgrade to HTTP/2. // TODO Move the client into the struct/new() // TODO Change the Connector Connect method to allow us to override the DNS // resolution in the connector! let alpn = AlpnConnector :: new ( ) ; let client = HyperClient :: builder ( ) . pool_idle_timeout ( Duration :: from_secs ( 30 ) ) . http2_only ( true ) . build :: < _ , hyper :: Body > ( alpn ) ; let question = & query . questions [ 0 ] ; let mut url = self . servers [ 0 ] . clone ( ) ; // TODO Support more than one server url . query_pairs_mut ( ) . append_pair ( " " , & question . name ) ; url . query_pairs_mut ( ) . append_pair ( " " , & question . r#type . to_string ( ) ) ; url . query_pairs_mut ( ) . append_pair ( " " , & query . cd . to_string ( ) ) ; url . query_pairs_mut ( ) . append_pair ( " " , CONTENT_TYPE_APPLICATION_DNS_JSON ) ; if let Some ( extension ) = & query . extension { url . query_pairs_mut ( ) . append_pair ( " " , & extension . dnssec_ok . to_string ( ) ) ; } // TODO Support the following // url.query_pairs_mut().append_pair("edns_client_subnet", ); // url.query_pairs_mut().append_pair("random_padding", ); // We have to do this wierd as_str().parse() thing because the // http::Uri doesn't provide a way to easily mutate or construct it. let uri : hyper :: Uri = url . as_str ( ) . parse ( ) ? ; let req = Request :: builder ( ) . method ( Method :: GET ) . uri ( uri ) . header ( ACCEPT , CONTENT_TYPE_APPLICATION_DNS_JSON ) . body ( Body :: empty ( ) ) ? ; let stats = StatsBuilder :: start ( 0 ) ; let resp = client . request ( req ) . await ? ; if let Some ( content_type ) = resp . headers ( ) . get ( CONTENT_TYPE ) { if ! content_type_equal ( content_type , CONTENT_TYPE_APPLICATION_DNS_JSON ) && ! content_type_equal ( content_type , CONTENT_TYPE_APPLICATION_X_JAVASCRIPT ) { bail ! ( InvalidData " " content_type CONTENT_TYPE_APPLICATION_DNS_JSON CONTENT_TYPE_APPLICATION_X_JAVASCRIPT ) ; } } if resp . status ( ) . is_success ( ) { // Get connection information (if available) let remote_addr = match resp . extensions ( ) . get :: < HttpInfo > ( ) { Some ( http_info ) => http_info . remote_addr ( ) , // TODO Maybe remote_addr should be optional? None => SocketAddr :: new ( IpAddr :: V4 ( Ipv4Addr :: new ( 0 , 0 , 0 , 0 ) ) , 0 ) , // Dummy address } ; // Read the full body let body = hyper :: body :: to_bytes ( resp . into_body ( ) ) . await ? ; println ! ( " " body ) ; let m : MessageJson = serde_json :: from_slice ( & body ) . map_err ( ParseError :: JsonError ) ? ; let mut m : Message = m . try_into ( ) ? ; m . stats = Some ( stats . end ( remote_addr , body . len ( ) ) ) ; return Ok ( m ) ; } // TODO Retry on 500s. If this is a 4xx we should not retry. Should we follow 3xx? bail ! ( InvalidInput " " resp status ( ) ) ; }
Sends the [`Message`] to the `server` via HTTP and returns the result.
Sends the [ ` Message ` ] to the ` server ` via HTTP and returns the result .
&self
query
&Message