From 39fe49c46c2bb8ca62c20c176899b8ae01342dc0 Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Mon, 19 Jun 2023 17:10:40 +0300 Subject: [PATCH] add client options --- plugins/http/guest-js/index.ts | 34 ++++++++++++++++++++++++++++++---- plugins/http/src/api-iife.js | 2 +- plugins/http/src/commands.rs | 11 +++++++++-- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/plugins/http/guest-js/index.ts b/plugins/http/guest-js/index.ts index dac17145..88622130 100644 --- a/plugins/http/guest-js/index.ts +++ b/plugins/http/guest-js/index.ts @@ -30,6 +30,21 @@ declare global { } } +/** + * Options to configure the Rust client used to make fetch requests + * + * @since 2.0.0 + */ +export interface ClientOptions { + /** + * Defines the maximum number of redirects the client should follow. + * If set to 0, no redirects will be followed. + */ + maxRedirections?: number; + /** Timeout in milliseconds */ + connectTimeout?: number; +} + /** * Fetch a resource from the network. It returns a `Promise` that resolves to the * `Response` to that `Request`, whether it is successful or not. @@ -41,11 +56,22 @@ declare global { * console.log(response.statusText); // e.g. "OK" * const jsonData = await response.json(); * ``` + * + * @since 2.0.0 */ -async function fetch( +export async function fetch( input: URL | Request | string, - init?: RequestInit + init?: RequestInit & ClientOptions ): Promise { + const maxRedirections = init?.maxRedirections; + const connectTimeout = init?.maxRedirections; + + // Remove these fields before creating the request + if (init) { + init.maxRedirections = undefined; + init.connectTimeout = undefined; + } + const req = new Request(input, init); const buffer = await req.arrayBuffer(); const reqData = buffer.byteLength ? Array.from(new Uint8Array(buffer)) : null; @@ -56,6 +82,8 @@ async function fetch( url: req.url, headers: Array.from(req.headers.entries()), data: reqData, + maxRedirections, + connectTimeout, }); req.signal.addEventListener("abort", () => { @@ -87,5 +115,3 @@ async function fetch( return res; } - -export { fetch }; diff --git a/plugins/http/src/api-iife.js b/plugins/http/src/api-iife.js index 722209c1..0944fcd0 100644 --- a/plugins/http/src/api-iife.js +++ b/plugins/http/src/api-iife.js @@ -1 +1 @@ -if("__TAURI__"in window){var __TAURI_HTTP__=function(t){"use strict";return t.fetch=async function(t,e){const r=new Request(t,e),_=await r.arrayBuffer(),n=_.byteLength?Array.from(new Uint8Array(_)):null,a=await window.__TAURI_INVOKE__("plugin:http|fetch",{cmd:"fetch",method:r.method,url:r.url,headers:Array.from(r.headers.entries()),data:n});r.signal.addEventListener("abort",(()=>{window.__TAURI_INVOKE__("plugin:http|fetch_cancel",{rid:a})}));const{status:i,statusText:s,url:d,headers:u,data:o}=await window.__TAURI_INVOKE__("plugin:http|fetch_send",{rid:a}),c=new Response(Uint8Array.from(o),{headers:u,status:i,statusText:s});return Object.defineProperty(c,"url",{value:d}),c},t}({});Object.defineProperty(window.__TAURI__,"http",{value:__TAURI_HTTP__})} +if("__TAURI__"in window){var __TAURI_HTTP__=function(t){"use strict";return t.fetch=async function(t,e){const n=null==e?void 0:e.maxRedirections,r=null==e?void 0:e.maxRedirections;e&&(e.maxRedirections=void 0,e.connectTimeout=void 0);const i=new Request(t,e),a=await i.arrayBuffer(),_=a.byteLength?Array.from(new Uint8Array(a)):null,o=await window.__TAURI_INVOKE__("plugin:http|fetch",{cmd:"fetch",method:i.method,url:i.url,headers:Array.from(i.headers.entries()),data:_,maxRedirections:n,connectTimeout:r});i.signal.addEventListener("abort",(()=>{window.__TAURI_INVOKE__("plugin:http|fetch_cancel",{rid:o})}));const{status:d,statusText:s,url:c,headers:u,data:l}=await window.__TAURI_INVOKE__("plugin:http|fetch_send",{rid:o}),h=new Response(Uint8Array.from(l),{headers:u,status:d,statusText:s});return Object.defineProperty(h,"url",{value:c}),h},t}({});Object.defineProperty(window.__TAURI__,"http",{value:__TAURI_HTTP__})} diff --git a/plugins/http/src/commands.rs b/plugins/http/src/commands.rs index d3b93c41..93a3adde 100644 --- a/plugins/http/src/commands.rs +++ b/plugins/http/src/commands.rs @@ -2,9 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use std::collections::HashMap; +use std::{collections::HashMap, time::Duration}; use http::{header, HeaderName, HeaderValue, Method, StatusCode}; +use reqwest::redirect::Policy; use tauri::{command, AppHandle, Runtime}; use crate::{Error, FetchRequest, FetchResponse, HttpExt, RequestId}; @@ -16,6 +17,8 @@ pub(crate) async fn fetch( url: String, headers: Vec<(String, String)>, data: Option>, + connect_timeout: u64, + max_redirections: usize, ) -> crate::Result { let url = url::Url::parse(&url)?; let scheme = url.scheme(); @@ -25,7 +28,11 @@ pub(crate) async fn fetch( match scheme { "http" | "https" => { if app.http().scope.is_allowed(&url) { - let mut request = reqwest::Client::new().request(method.clone(), url); + let mut request = reqwest::ClientBuilder::new() + .connect_timeout(Duration::from_millis(connect_timeout)) + .redirect(Policy::limited(max_redirections)) + .build()? + .request(method.clone(), url); for (key, value) in &headers { let name = HeaderName::from_bytes(key.as_bytes())?;