qiniu-http-client 0.2.2

Qiniu HTTP Client for Rust
Documentation
use super::{
    super::{
        super::{DomainWithPort, IpAddrWithPort},
        ChooserFeedback, InnerRequestParts, RetriedStatsInfo, SimplifiedCallbackContext, SyncResponse,
    },
    domain_or_ip_addr::DomainOrIpAddr,
    error::{TryError, TryErrorWithExtensions},
    send_http_request::send_http_request,
    utils::{
        call_after_request_signed_callbacks, call_before_request_signed_callbacks, extract_ips_from, make_request,
        make_url, reset_request_body, sign_request,
    },
};
use qiniu_http::{
    Extensions, HeaderName, HeaderValue, Metrics, OnHeaderCallback, OnProgressCallback, OnStatusCodeCallback,
    Request as HttpRequest, RequestParts as HttpRequestParts, StatusCode, SyncRequestBody, TransferProgressInfo,
};
use std::mem::take;

pub(super) fn try_domain_or_ip_addr(
    domain_or_ip: &DomainOrIpAddr,
    parts: &InnerRequestParts<'_>,
    body: &mut SyncRequestBody<'_>,
    mut extensions: Extensions,
    retried: &mut RetriedStatsInfo,
) -> Result<SyncResponse, TryErrorWithExtensions> {
    let (url, resolved_ips) =
        make_url(domain_or_ip, parts, retried).map_err(|err| err.with_extensions(take(&mut extensions)))?;
    let on_uploading_progress = |info: TransferProgressInfo<'_>| parts.call_uploading_progress_callbacks(parts, info);
    let on_receive_response_status =
        |status_code: StatusCode| parts.call_receive_response_status_callbacks(parts, status_code);
    let on_receive_response_header =
        |name: &HeaderName, value: &HeaderValue| parts.call_receive_response_header_callbacks(parts, name, value);
    let mut http_request: HttpRequest<SyncRequestBody> =
        make_request(url, parts, body.into(), extensions, &resolved_ips);
    reset_request_body(http_request.body_mut(), retried).map_err(|err| err.with_request(&mut http_request))?;
    call_before_request_signed_callbacks(parts, &mut http_request, retried)
        .map_err(|err| err.with_request(&mut http_request))?;
    sign_request(&mut http_request, parts.authorization(), retried)
        .map_err(|err| err.with_request(&mut http_request))?;
    call_after_request_signed_callbacks(parts, &mut http_request, retried)
        .map_err(|err| err.with_request(&mut http_request))?;
    reset_request_body(http_request.body_mut(), retried).map_err(|err| err.with_request(&mut http_request))?;

    if parts.uploading_progress_callbacks_count() > 0 {
        *http_request.on_uploading_progress_mut() = Some(OnProgressCallback::reference(&on_uploading_progress));
    }
    if parts.receive_response_status_callbacks_count() > 0 {
        *http_request.on_receive_response_status_mut() =
            Some(OnStatusCodeCallback::reference(&on_receive_response_status));
    }
    if parts.receive_response_header_callbacks_count() > 0 {
        *http_request.on_receive_response_header_mut() = Some(OnHeaderCallback::reference(&on_receive_response_header));
    }

    let (extracted_ips, domain) = extract_ips_from(domain_or_ip);
    match send_http_request(&mut http_request, parts, retried) {
        Ok(response) => {
            if !extracted_ips.is_empty() {
                parts.http_client().chooser().feedback(make_positive_feedback(
                    &extracted_ips,
                    domain,
                    &mut http_request,
                    response.metrics(),
                    retried,
                ));
            }
            Ok(response)
        }
        Err(err) => {
            if !extracted_ips.is_empty() {
                parts.http_client().chooser().feedback(make_negative_feedback(
                    &extracted_ips,
                    domain,
                    &mut http_request,
                    &err,
                    retried,
                ));
            }
            Err(err.with_request(&mut http_request))
        }
    }
}

fn make_positive_feedback<'f>(
    ips: &'f [IpAddrWithPort],
    domain: Option<&'f DomainWithPort>,
    parts: &'f mut HttpRequestParts,
    metrics: Option<&'f Metrics>,
    retried: &'f RetriedStatsInfo,
) -> ChooserFeedback<'f> {
    let mut builder = ChooserFeedback::builder(ips);
    builder.retried(retried).extensions(parts.extensions_mut());
    if let Some(domain) = domain {
        builder.domain(domain);
    }
    if let Some(metrics) = metrics {
        builder.metrics(metrics);
    }
    builder.build()
}

fn make_negative_feedback<'f>(
    ips: &'f [IpAddrWithPort],
    domain: Option<&'f DomainWithPort>,
    parts: &'f mut HttpRequestParts,
    err: &'f TryError,
    retried: &'f RetriedStatsInfo,
) -> ChooserFeedback<'f> {
    let mut builder = ChooserFeedback::builder(ips);
    builder.retried(retried).extensions(parts.extensions_mut());
    if let Some(domain) = domain {
        builder.domain(domain);
    }
    if let Some(metrics) = err.response_error().metrics() {
        builder.metrics(metrics);
    }
    if let Some(error) = err.feedback_response_error() {
        builder.error(error);
    }
    builder.build()
}

#[cfg(feature = "async")]
use super::{
    super::super::{AsyncRequestBody, AsyncResponse},
    send_http_request::async_send_http_request,
    utils::{reset_async_request_body, sign_async_request},
};

#[cfg(feature = "async")]
pub(super) async fn async_try_domain_or_ip_addr(
    domain_or_ip: &DomainOrIpAddr,
    parts: &InnerRequestParts<'_>,
    body: &mut AsyncRequestBody<'_>,
    mut extensions: Extensions,
    retried: &mut RetriedStatsInfo,
) -> Result<AsyncResponse, TryErrorWithExtensions> {
    let (url, resolved_ips) =
        make_url(domain_or_ip, parts, retried).map_err(|err| err.with_extensions(take(&mut extensions)))?;
    let on_uploading_progress = |info: TransferProgressInfo<'_>| parts.call_uploading_progress_callbacks(parts, info);
    let on_receive_response_status =
        |status_code: StatusCode| parts.call_receive_response_status_callbacks(parts, status_code);
    let on_receive_response_header =
        |name: &HeaderName, value: &HeaderValue| parts.call_receive_response_header_callbacks(parts, name, value);
    let mut http_request: HttpRequest<AsyncRequestBody> =
        make_request(url, parts, body.into(), extensions, &resolved_ips);
    reset_async_request_body(http_request.body_mut(), retried)
        .await
        .map_err(|err| err.with_request(&mut http_request))?;
    call_before_request_signed_callbacks(parts, &mut http_request, retried)
        .map_err(|err| err.with_request(&mut http_request))?;
    sign_async_request(&mut http_request, parts.authorization(), retried)
        .await
        .map_err(|err| err.with_request(&mut http_request))?;
    call_after_request_signed_callbacks(parts, &mut http_request, retried)
        .map_err(|err| err.with_request(&mut http_request))?;
    reset_async_request_body(http_request.body_mut(), retried)
        .await
        .map_err(|err| err.with_request(&mut http_request))?;

    if parts.uploading_progress_callbacks_count() > 0 {
        *http_request.on_uploading_progress_mut() = Some(OnProgressCallback::reference(&on_uploading_progress));
    }
    if parts.receive_response_status_callbacks_count() > 0 {
        *http_request.on_receive_response_status_mut() =
            Some(OnStatusCodeCallback::reference(&on_receive_response_status));
    }
    if parts.receive_response_header_callbacks_count() > 0 {
        *http_request.on_receive_response_header_mut() = Some(OnHeaderCallback::reference(&on_receive_response_header));
    }

    let (extracted_ips, domain) = extract_ips_from(domain_or_ip);
    match async_send_http_request(&mut http_request, parts, retried).await {
        Ok(response) => {
            if !extracted_ips.is_empty() {
                parts
                    .http_client()
                    .chooser()
                    .async_feedback(make_positive_feedback(
                        &extracted_ips,
                        domain,
                        &mut http_request,
                        response.metrics(),
                        retried,
                    ))
                    .await;
            }
            Ok(response)
        }
        Err(err) => {
            if !extracted_ips.is_empty() {
                parts
                    .http_client()
                    .chooser()
                    .async_feedback(make_negative_feedback(
                        &extracted_ips,
                        domain,
                        &mut http_request,
                        &err,
                        retried,
                    ))
                    .await;
            }
            Err(err.with_request(&mut http_request))
        }
    }
}