mirror of
https://github.com/chatmail/core.git
synced 2026-04-21 15:36:30 +03:00
feat: replace reqwest with hyper
This change replaces usage of `reqwest` and `hyper-util` with custom connection establishment code so it is done in the same way as for IMAP and SMTP connections. This way we control HTTP, IMAP and SMTP connection establishment and schedule connection attempts to resolved IP addresses in the same way for all 3 protocols.
This commit is contained in:
@@ -2,12 +2,14 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{Context as _, Result};
|
||||
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::context::Context;
|
||||
use crate::net::http::post_form;
|
||||
use crate::net::read_url_blob;
|
||||
use crate::provider;
|
||||
use crate::provider::Oauth2Authorizer;
|
||||
use crate::tools::time;
|
||||
@@ -159,25 +161,19 @@ pub(crate) async fn get_oauth2_access_token(
|
||||
|
||||
// ... and POST
|
||||
|
||||
// All OAuth URLs are hardcoded HTTPS URLs,
|
||||
// so it is safe to load DNS cache.
|
||||
let load_cache = true;
|
||||
|
||||
let client = crate::net::http::get_client(context, load_cache).await?;
|
||||
|
||||
let response: Response = match client.post(post_url).form(&post_param).send().await {
|
||||
Ok(resp) => match resp.json().await {
|
||||
let response: Response = match post_form(context, post_url, &post_param).await {
|
||||
Ok(resp) => match serde_json::from_slice(&resp) {
|
||||
Ok(response) => response,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
context,
|
||||
"Failed to parse OAuth2 JSON response from {}: error: {}", token_url, err
|
||||
"Failed to parse OAuth2 JSON response from {token_url}: {err:#}."
|
||||
);
|
||||
return Ok(None);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
warn!(context, "Error calling OAuth2 at {}: {:?}", token_url, err);
|
||||
warn!(context, "Error calling OAuth2 at {token_url}: {err:#}.");
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
@@ -246,11 +242,20 @@ pub(crate) async fn get_oauth2_addr(
|
||||
}
|
||||
|
||||
if let Some(access_token) = get_oauth2_access_token(context, addr, code, false).await? {
|
||||
let addr_out = oauth2.get_addr(context, &access_token).await;
|
||||
let addr_out = match oauth2.get_addr(context, &access_token).await {
|
||||
Ok(addr) => addr,
|
||||
Err(err) => {
|
||||
warn!(context, "Error getting addr: {err:#}.");
|
||||
None
|
||||
}
|
||||
};
|
||||
if addr_out.is_none() {
|
||||
// regenerate
|
||||
if let Some(access_token) = get_oauth2_access_token(context, addr, code, true).await? {
|
||||
Ok(oauth2.get_addr(context, &access_token).await)
|
||||
Ok(oauth2
|
||||
.get_addr(context, &access_token)
|
||||
.await
|
||||
.unwrap_or_default())
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -282,7 +287,7 @@ impl Oauth2 {
|
||||
None
|
||||
}
|
||||
|
||||
async fn get_addr(&self, context: &Context, access_token: &str) -> Option<String> {
|
||||
async fn get_addr(&self, context: &Context, access_token: &str) -> Result<Option<String>> {
|
||||
let userinfo_url = self.get_userinfo.unwrap_or("");
|
||||
let userinfo_url = replace_in_uri(userinfo_url, "$ACCESS_TOKEN", access_token);
|
||||
|
||||
@@ -294,44 +299,21 @@ impl Oauth2 {
|
||||
// "picture": "https://lh4.googleusercontent.com/-Gj5jh_9R0BY/AAAAAAAAAAI/AAAAAAAAAAA/IAjtjfjtjNA/photo.jpg"
|
||||
// }
|
||||
|
||||
// All OAuth URLs are hardcoded HTTPS URLs,
|
||||
// so it is safe to load DNS cache.
|
||||
let load_cache = true;
|
||||
|
||||
let client = match crate::net::http::get_client(context, load_cache).await {
|
||||
Ok(cl) => cl,
|
||||
Err(err) => {
|
||||
warn!(context, "failed to get HTTP client: {}", err);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let response = match client.get(userinfo_url).send().await {
|
||||
Ok(response) => response,
|
||||
Err(err) => {
|
||||
warn!(context, "failed to get userinfo: {}", err);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let response: Result<HashMap<String, serde_json::Value>, _> = response.json().await;
|
||||
let parsed = match response {
|
||||
Ok(parsed) => parsed,
|
||||
Err(err) => {
|
||||
warn!(context, "Error getting userinfo: {}", err);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let response = read_url_blob(context, &userinfo_url).await?;
|
||||
let parsed: HashMap<String, serde_json::Value> =
|
||||
serde_json::from_slice(&response.blob).context("Error getting userinfo")?;
|
||||
// CAVE: serde_json::Value.as_str() removes the quotes of json-strings
|
||||
// but serde_json::Value.to_string() does not!
|
||||
if let Some(addr) = parsed.get("email") {
|
||||
if let Some(s) = addr.as_str() {
|
||||
Some(s.to_string())
|
||||
Ok(Some(s.to_string()))
|
||||
} else {
|
||||
warn!(context, "E-mail in userinfo is not a string: {}", addr);
|
||||
None
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
warn!(context, "E-mail missing in userinfo.");
|
||||
None
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user