55use std:: { collections:: HashMap , time:: Duration } ;
66
77use http:: { header, HeaderName , HeaderValue , Method , StatusCode } ;
8- use reqwest:: redirect:: Policy ;
9- use serde:: Serialize ;
8+ use reqwest:: { redirect:: Policy , NoProxy } ;
9+ use serde:: { Deserialize , Serialize } ;
1010use tauri:: { command, AppHandle , Runtime } ;
1111
1212use crate :: { Error , FetchRequest , HttpExt , RequestId } ;
@@ -20,16 +20,111 @@ pub struct FetchResponse {
2020 url : String ,
2121}
2222
23- #[ command ]
24- pub async fn fetch < R : Runtime > (
25- app : AppHandle < R > ,
23+ #[ derive ( Deserialize ) ]
24+ # [ serde ( rename_all = "camelCase" ) ]
25+ pub struct ClientConfig {
2626 method : String ,
2727 url : url:: Url ,
2828 headers : Vec < ( String , String ) > ,
2929 data : Option < Vec < u8 > > ,
3030 connect_timeout : Option < u64 > ,
3131 max_redirections : Option < usize > ,
32+ proxy : Option < Proxy > ,
33+ }
34+
35+ #[ derive( Deserialize ) ]
36+ #[ serde( rename_all = "camelCase" ) ]
37+ pub struct Proxy {
38+ all : Option < UrlOrConfig > ,
39+ http : Option < UrlOrConfig > ,
40+ https : Option < UrlOrConfig > ,
41+ }
42+
43+ #[ derive( Deserialize ) ]
44+ #[ serde( rename_all = "camelCase" ) ]
45+ #[ serde( untagged) ]
46+ pub enum UrlOrConfig {
47+ Url ( String ) ,
48+ Config ( ProxyConfig ) ,
49+ }
50+
51+ #[ derive( Deserialize ) ]
52+ #[ serde( rename_all = "camelCase" ) ]
53+ pub struct ProxyConfig {
54+ url : String ,
55+ basic_auth : Option < BasicAuth > ,
56+ no_proxy : Option < String > ,
57+ }
58+
59+ #[ derive( Deserialize ) ]
60+ pub struct BasicAuth {
61+ username : String ,
62+ password : String ,
63+ }
64+
65+ #[ inline]
66+ fn proxy_creator (
67+ url_or_config : UrlOrConfig ,
68+ proxy_fn : fn ( String ) -> reqwest:: Result < reqwest:: Proxy > ,
69+ ) -> reqwest:: Result < reqwest:: Proxy > {
70+ match url_or_config {
71+ UrlOrConfig :: Url ( url) => Ok ( proxy_fn ( url) ?) ,
72+ UrlOrConfig :: Config ( ProxyConfig {
73+ url,
74+ basic_auth,
75+ no_proxy,
76+ } ) => {
77+ let mut proxy = proxy_fn ( url) ?;
78+ if let Some ( basic_auth) = basic_auth {
79+ proxy = proxy. basic_auth ( & basic_auth. username , & basic_auth. password ) ;
80+ }
81+ if let Some ( no_proxy) = no_proxy {
82+ proxy = proxy. no_proxy ( NoProxy :: from_string ( & no_proxy) ) ;
83+ }
84+ Ok ( proxy)
85+ }
86+ }
87+ }
88+
89+ fn attach_proxy (
90+ proxy : Proxy ,
91+ mut builder : reqwest:: ClientBuilder ,
92+ ) -> crate :: Result < reqwest:: ClientBuilder > {
93+ let Proxy { all, http, https } = proxy;
94+
95+ if let Some ( all) = all {
96+ let proxy = proxy_creator ( all, reqwest:: Proxy :: all) ?;
97+ builder = builder. proxy ( proxy) ;
98+ }
99+
100+ if let Some ( http) = http {
101+ let proxy = proxy_creator ( http, reqwest:: Proxy :: http) ?;
102+ builder = builder. proxy ( proxy) ;
103+ }
104+
105+ if let Some ( https) = https {
106+ let proxy = proxy_creator ( https, reqwest:: Proxy :: https) ?;
107+ builder = builder. proxy ( proxy) ;
108+ }
109+
110+ Ok ( builder)
111+ }
112+
113+ #[ command]
114+ pub async fn fetch < R : Runtime > (
115+ app : AppHandle < R > ,
116+ client_config : ClientConfig ,
32117) -> crate :: Result < RequestId > {
118+ let ClientConfig {
119+ method,
120+ url,
121+ headers,
122+ data,
123+ connect_timeout,
124+ max_redirections,
125+ proxy,
126+ } = client_config;
127+
33128 let scheme = url. scheme ( ) ;
34129 let method = Method :: from_bytes ( method. as_bytes ( ) ) ?;
35130 let headers: HashMap < String , String > = HashMap :: from_iter ( headers) ;
@@ -51,6 +146,10 @@ pub async fn fetch<R: Runtime>(
51146 } ) ;
52147 }
53148
149+ if let Some ( proxy_config) = proxy {
150+ builder = attach_proxy ( proxy_config, builder) ?;
151+ }
152+
54153 let mut request = builder. build ( ) ?. request ( method. clone ( ) , url) ;
55154
56155 for ( key, value) in & headers {
0 commit comments