mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-18 15:33:52 +01:00
Connection re-use for plugin networking and beta NTLM plugin (#295)
This commit is contained in:
@@ -6,9 +6,9 @@ use http::header::{ACCEPT, USER_AGENT};
|
||||
use http::{HeaderMap, HeaderName, HeaderValue};
|
||||
use log::{debug, error, warn};
|
||||
use mime_guess::Mime;
|
||||
use reqwest::redirect::Policy;
|
||||
use reqwest::{Method, NoProxy, Response};
|
||||
use reqwest::{Proxy, Url, multipart};
|
||||
use reqwest::{Method, Response};
|
||||
use reqwest::{Url, multipart};
|
||||
use reqwest_cookie_store::{CookieStore, CookieStoreMutex};
|
||||
use serde_json::Value;
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::PathBuf;
|
||||
@@ -21,6 +21,10 @@ use tokio::fs::{File, create_dir_all};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::sync::watch::Receiver;
|
||||
use tokio::sync::{Mutex, oneshot};
|
||||
use yaak_http::client::{
|
||||
HttpConnectionOptions, HttpConnectionProxySetting, HttpConnectionProxySettingAuth,
|
||||
};
|
||||
use yaak_http::manager::HttpConnectionManager;
|
||||
use yaak_models::models::{
|
||||
Cookie, CookieJar, Environment, HttpRequest, HttpResponse, HttpResponseHeader,
|
||||
HttpResponseState, ProxySetting, ProxySettingAuth,
|
||||
@@ -28,12 +32,11 @@ use yaak_models::models::{
|
||||
use yaak_models::query_manager::QueryManagerExt;
|
||||
use yaak_models::util::UpdateSource;
|
||||
use yaak_plugins::events::{
|
||||
CallHttpAuthenticationRequest, HttpHeader, PluginWindowContext, RenderPurpose,
|
||||
CallHttpAuthenticationRequest, HttpHeader, PluginContext, RenderPurpose,
|
||||
};
|
||||
use yaak_plugins::manager::PluginManager;
|
||||
use yaak_plugins::template_callback::PluginTemplateCallback;
|
||||
use yaak_templates::{RenderErrorBehavior, RenderOptions};
|
||||
use crate::dns::LocalhostResolver;
|
||||
|
||||
pub async fn send_http_request<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
@@ -42,9 +45,31 @@ pub async fn send_http_request<R: Runtime>(
|
||||
environment: Option<Environment>,
|
||||
cookie_jar: Option<CookieJar>,
|
||||
cancelled_rx: &mut Receiver<bool>,
|
||||
) -> Result<HttpResponse> {
|
||||
send_http_request_with_context(
|
||||
window,
|
||||
unrendered_request,
|
||||
og_response,
|
||||
environment,
|
||||
cookie_jar,
|
||||
cancelled_rx,
|
||||
&PluginContext::new(window),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn send_http_request_with_context<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
unrendered_request: &HttpRequest,
|
||||
og_response: &HttpResponse,
|
||||
environment: Option<Environment>,
|
||||
cookie_jar: Option<CookieJar>,
|
||||
cancelled_rx: &mut Receiver<bool>,
|
||||
plugin_context: &PluginContext,
|
||||
) -> Result<HttpResponse> {
|
||||
let app_handle = window.app_handle().clone();
|
||||
let plugin_manager = app_handle.state::<PluginManager>();
|
||||
let connection_manager = app_handle.state::<HttpConnectionManager>();
|
||||
let settings = window.db().get_settings();
|
||||
let workspace = window.db().get_workspace(&unrendered_request.workspace_id)?;
|
||||
let environment_id = environment.map(|e| e.id);
|
||||
@@ -72,11 +97,7 @@ pub async fn send_http_request<R: Runtime>(
|
||||
}
|
||||
};
|
||||
|
||||
let cb = PluginTemplateCallback::new(
|
||||
window.app_handle(),
|
||||
&PluginWindowContext::new(window),
|
||||
RenderPurpose::Send,
|
||||
);
|
||||
let cb = PluginTemplateCallback::new(window.app_handle(), &plugin_context, RenderPurpose::Send);
|
||||
|
||||
let opt = RenderOptions {
|
||||
error_behavior: RenderErrorBehavior::Throw,
|
||||
@@ -102,65 +123,33 @@ pub async fn send_http_request<R: Runtime>(
|
||||
}
|
||||
debug!("Sending request to {} {url_string}", request.method);
|
||||
|
||||
let mut client_builder = reqwest::Client::builder()
|
||||
.redirect(match workspace.setting_follow_redirects {
|
||||
true => Policy::limited(10), // TODO: Handle redirects natively
|
||||
false => Policy::none(),
|
||||
})
|
||||
.connection_verbose(true)
|
||||
.gzip(true)
|
||||
.brotli(true)
|
||||
.deflate(true)
|
||||
.dns_resolver(LocalhostResolver::new())
|
||||
.referer(false)
|
||||
.tls_info(true);
|
||||
|
||||
let tls_config = yaak_http::tls::get_config(workspace.setting_validate_certificates, true);
|
||||
client_builder = client_builder.use_preconfigured_tls(tls_config);
|
||||
|
||||
match settings.proxy {
|
||||
Some(ProxySetting::Disabled) => client_builder = client_builder.no_proxy(),
|
||||
let proxy_setting = match settings.proxy {
|
||||
None => HttpConnectionProxySetting::System,
|
||||
Some(ProxySetting::Disabled) => HttpConnectionProxySetting::Disabled,
|
||||
Some(ProxySetting::Enabled {
|
||||
http,
|
||||
https,
|
||||
auth,
|
||||
disabled,
|
||||
bypass,
|
||||
}) if !disabled => {
|
||||
debug!("Using proxy http={http} https={https} bypass={bypass}");
|
||||
if !http.is_empty() {
|
||||
match Proxy::http(http) {
|
||||
Ok(mut proxy) => {
|
||||
if let Some(ProxySettingAuth { user, password }) = auth.clone() {
|
||||
debug!("Using http proxy auth");
|
||||
proxy = proxy.basic_auth(user.as_str(), password.as_str());
|
||||
disabled,
|
||||
}) => {
|
||||
if disabled {
|
||||
HttpConnectionProxySetting::System
|
||||
} else {
|
||||
HttpConnectionProxySetting::Enabled {
|
||||
http,
|
||||
https,
|
||||
bypass,
|
||||
auth: match auth {
|
||||
None => None,
|
||||
Some(ProxySettingAuth { user, password }) => {
|
||||
Some(HttpConnectionProxySettingAuth { user, password })
|
||||
}
|
||||
proxy = proxy.no_proxy(NoProxy::from_string(&bypass));
|
||||
client_builder = client_builder.proxy(proxy);
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to apply http proxy {e:?}");
|
||||
}
|
||||
};
|
||||
}
|
||||
if !https.is_empty() {
|
||||
match Proxy::https(https) {
|
||||
Ok(mut proxy) => {
|
||||
if let Some(ProxySettingAuth { user, password }) = auth {
|
||||
debug!("Using https proxy auth");
|
||||
proxy = proxy.basic_auth(user.as_str(), password.as_str());
|
||||
}
|
||||
proxy = proxy.no_proxy(NoProxy::from_string(&bypass));
|
||||
client_builder = client_builder.proxy(proxy);
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to apply https proxy {e:?}");
|
||||
}
|
||||
};
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {} // Nothing to do for this one, as it is the default
|
||||
}
|
||||
};
|
||||
|
||||
// Add cookie store if specified
|
||||
let maybe_cookie_manager = match cookie_jar.clone() {
|
||||
@@ -179,23 +168,33 @@ pub async fn send_http_request<R: Runtime>(
|
||||
.map(|c| Ok(c))
|
||||
.collect::<Vec<Result<_>>>();
|
||||
|
||||
let store = reqwest_cookie_store::CookieStore::from_cookies(cookies, true)?;
|
||||
let cookie_store = reqwest_cookie_store::CookieStoreMutex::new(store);
|
||||
let cookie_store = CookieStore::from_cookies(cookies, true)?;
|
||||
let cookie_store = CookieStoreMutex::new(cookie_store);
|
||||
let cookie_store = Arc::new(cookie_store);
|
||||
client_builder = client_builder.cookie_provider(Arc::clone(&cookie_store));
|
||||
|
||||
Some((cookie_store, cj))
|
||||
let cookie_provider = Arc::clone(&cookie_store);
|
||||
Some((cookie_provider, cj))
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
if workspace.setting_request_timeout > 0 {
|
||||
client_builder = client_builder.timeout(Duration::from_millis(
|
||||
workspace.setting_request_timeout.unsigned_abs() as u64,
|
||||
));
|
||||
}
|
||||
|
||||
let client = client_builder.build()?;
|
||||
let client = connection_manager
|
||||
.get_client(
|
||||
&plugin_context.id,
|
||||
&HttpConnectionOptions {
|
||||
follow_redirects: workspace.setting_follow_redirects,
|
||||
validate_certificates: workspace.setting_validate_certificates,
|
||||
proxy: proxy_setting,
|
||||
cookie_provider: maybe_cookie_manager.as_ref().map(|(p, _)| Arc::clone(&p)),
|
||||
timeout: if workspace.setting_request_timeout > 0 {
|
||||
Some(Duration::from_millis(
|
||||
workspace.setting_request_timeout.unsigned_abs() as u64
|
||||
))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Render query parameters
|
||||
let mut query_params = Vec::new();
|
||||
@@ -469,8 +468,9 @@ pub async fn send_http_request<R: Runtime>(
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
let auth_result =
|
||||
plugin_manager.call_http_authentication(&window, &authentication_type, req).await;
|
||||
let auth_result = plugin_manager
|
||||
.call_http_authentication(&window, &authentication_type, req, plugin_context)
|
||||
.await;
|
||||
let plugin_result = match auth_result {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
|
||||
Reference in New Issue
Block a user