Mercurial > lbo > hg > async-google-apis
view async-google-apis-common/src/http.rs @ 67:c7768b877690
Implement global API parameters
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Mon, 19 Oct 2020 23:08:05 +0200 |
parents | fe548002c2e5 |
children | 171be899018e |
line wrap: on
line source
use crate::*; /// This type is used as type parameter to the following functions, when `rq` is `None`. #[derive(Serialize)] pub struct EmptyRequest {} /// The Content-Type header is set automatically to application/json. pub async fn do_request<Req: Serialize, Resp: DeserializeOwned + Clone>( cl: &TlsClient, path: &str, headers: &[(String, String)], http_method: &str, rq: Option<Req>, ) -> Result<Resp> { let mut reqb = hyper::Request::builder().uri(path).method(http_method); for (k, v) in headers { reqb = reqb.header(k, v); } reqb = reqb.header("Content-Type", "application/json"); let body_str; if let Some(rq) = rq { body_str = serde_json::to_string(&rq)?; } else { body_str = "".to_string(); } let body; if body_str == "null" { body = hyper::Body::from(""); } else { body = hyper::Body::from(body_str); } let http_request = reqb.body(body)?; debug!("do_request: Launching HTTP request: {:?}", http_request); let http_response = cl.request(http_request).await?; let status = http_response.status(); debug!("do_request: HTTP response with status {} received: {:?}", status, http_response); let response_body = hyper::body::to_bytes(http_response.into_body()).await?; let response_body_str = String::from_utf8(response_body.to_vec()); if !status.is_success() { Err(Error::new(ApiError::HTTPError( status, response_body_str.unwrap_or("".to_string()), ))) } else { serde_json::from_reader(response_body.as_ref()).map_err(Error::from) } } /// The Content-Length header is set automatically. pub async fn do_upload_multipart<Req: Serialize, Resp: DeserializeOwned + Clone>( cl: &TlsClient, path: &str, headers: &[(String, String)], http_method: &str, req: Option<Req>, data: hyper::body::Bytes, ) -> Result<Resp> { let mut reqb = hyper::Request::builder().uri(path).method(http_method); for (k, v) in headers { reqb = reqb.header(k, v); } let data = multipart::format_multipart(&req, data)?; reqb = reqb.header("Content-Length", data.as_ref().len()); reqb = reqb.header( "Content-Type", format!("multipart/related; boundary={}", multipart::MIME_BOUNDARY), ); let body = hyper::Body::from(data.as_ref().to_vec()); let http_request = reqb.body(body)?; debug!("do_upload_multipart: Launching HTTP request: {:?}", http_request); let http_response = cl.request(http_request).await?; let status = http_response.status(); debug!("do_upload_multipart: HTTP response with status {} received: {:?}", status, http_response); let response_body = hyper::body::to_bytes(http_response.into_body()).await?; let response_body_str = String::from_utf8(response_body.to_vec()); if !status.is_success() { Err(Error::new(ApiError::HTTPError( status, response_body_str.unwrap_or("".to_string()), ))) } else { serde_json::from_reader(response_body.as_ref()).map_err(Error::from) } } pub async fn do_download<Req: Serialize>( cl: &TlsClient, path: &str, headers: &[(String, String)], http_method: &str, rq: Option<Req>, dst: &mut dyn std::io::Write, ) -> Result<()> { let mut path = path.to_string(); let mut http_response; let mut i = 0; // Follow redirects. loop { let mut reqb = hyper::Request::builder().uri(&path).method(http_method); for (k, v) in headers { reqb = reqb.header(k, v); } let body_str = serde_json::to_string(&rq)?; let body; if body_str == "null" { body = hyper::Body::from(""); } else { body = hyper::Body::from(body_str); } let http_request = reqb.body(body)?; debug!("do_download: Redirect {}, Launching HTTP request: {:?}", i, http_request); http_response = Some(cl.request(http_request).await?); let status = http_response.as_ref().unwrap().status(); debug!("do_download: Redirect {}, HTTP response with status {} received: {:?}", i, status, http_response); if status.is_success() { break; } else if status.is_redirection() { i += 1; let new_location = http_response .as_ref() .unwrap() .headers() .get(hyper::header::LOCATION); if new_location.is_none() { return Err(Error::new(ApiError::HTTPError( status, format!("Redirect doesn't contain a Location: header"), ))); } path = new_location.unwrap().to_str()?.to_string(); continue; } else if !status.is_success() { return Err(Error::new(ApiError::HTTPError(status, String::new()))); } } let response_body = http_response.unwrap().into_body(); let write_results = response_body .map(move |chunk| dst.write(chunk?.as_ref()).map(|_| ()).map_err(Error::from)) .collect::<Vec<Result<()>>>() .await; if let Some(e) = write_results.into_iter().find(|r| r.is_err()) { return e; } Ok(()) }