feat(http): enable cookies and set origin header (#1192)

pull/1315/head
Amr Bashir 1 year ago committed by GitHub
parent 463f5971eb
commit 58330f9ec1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"http": "patch"
---
Enable cookies store feature flag by default.

@ -0,0 +1,5 @@
---
"http": "patch"
---
Set the request origin to the current webview url.

@ -39,7 +39,8 @@ default = [
"rustls-tls", "rustls-tls",
"http2", "http2",
"charset", "charset",
"macos-system-configuration" "macos-system-configuration",
"cookies"
] ]
multipart = [ "reqwest/multipart" ] multipart = [ "reqwest/multipart" ]
json = [ "reqwest/json" ] json = [ "reqwest/json" ]

@ -4,19 +4,19 @@
use std::{collections::HashMap, future::Future, pin::Pin, sync::Arc, time::Duration}; use std::{collections::HashMap, future::Future, pin::Pin, sync::Arc, time::Duration};
use http::{header, HeaderName, HeaderValue, Method, StatusCode}; use http::{header, HeaderName, Method, StatusCode};
use reqwest::{redirect::Policy, NoProxy}; use reqwest::{redirect::Policy, NoProxy};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tauri::{ use tauri::{
async_runtime::Mutex, async_runtime::Mutex,
command, command,
ipc::{CommandScope, GlobalScope}, ipc::{CommandScope, GlobalScope},
Manager, ResourceId, Runtime, Webview, Manager, ResourceId, Runtime, State, Webview,
}; };
use crate::{ use crate::{
scope::{Entry, Scope}, scope::{Entry, Scope},
Error, Result, Error, Http, Result,
}; };
struct ReqwestResponse(reqwest::Response); struct ReqwestResponse(reqwest::Response);
@ -138,6 +138,7 @@ fn attach_proxy(
#[command] #[command]
pub async fn fetch<R: Runtime>( pub async fn fetch<R: Runtime>(
webview: Webview<R>, webview: Webview<R>,
state: State<'_, Http>,
client_config: ClientConfig, client_config: ClientConfig,
command_scope: CommandScope<Entry>, command_scope: CommandScope<Entry>,
global_scope: GlobalScope<Entry>, global_scope: GlobalScope<Entry>,
@ -190,11 +191,15 @@ pub async fn fetch<R: Runtime>(
builder = attach_proxy(proxy_config, builder)?; builder = attach_proxy(proxy_config, builder)?;
} }
#[cfg(feature = "cookies")]
{
builder = builder.cookie_provider(state.cookies_jar.clone());
}
let mut request = builder.build()?.request(method.clone(), url); let mut request = builder.build()?.request(method.clone(), url);
for (name, value) in &headers { for (name, value) in &headers {
let name = HeaderName::from_bytes(name.as_bytes())?; let name = HeaderName::from_bytes(name.as_bytes())?;
let value = HeaderValue::from_bytes(value.as_bytes())?;
#[cfg(not(feature = "unsafe-headers"))] #[cfg(not(feature = "unsafe-headers"))]
if matches!( if matches!(
name, name,
@ -228,22 +233,21 @@ pub async fn fetch<R: Runtime>(
// POST and PUT requests should always have a 0 length content-length, // POST and PUT requests should always have a 0 length content-length,
// if there is no body. https://fetch.spec.whatwg.org/#http-network-or-cache-fetch // if there is no body. https://fetch.spec.whatwg.org/#http-network-or-cache-fetch
if data.is_none() && matches!(method, Method::POST | Method::PUT) { if data.is_none() && matches!(method, Method::POST | Method::PUT) {
request = request.header(header::CONTENT_LENGTH, HeaderValue::from(0)); request = request.header(header::CONTENT_LENGTH, 0);
} }
if headers.contains_key(header::RANGE.as_str()) { if headers.contains_key(header::RANGE.as_str()) {
// https://fetch.spec.whatwg.org/#http-network-or-cache-fetch step 18 // https://fetch.spec.whatwg.org/#http-network-or-cache-fetch step 18
// If httpRequests header list contains `Range`, then append (`Accept-Encoding`, `identity`) // If httpRequests header list contains `Range`, then append (`Accept-Encoding`, `identity`)
request = request.header( request = request.header(header::ACCEPT_ENCODING, "identity");
header::ACCEPT_ENCODING,
HeaderValue::from_static("identity"),
);
} }
if !headers.contains_key(header::USER_AGENT.as_str()) { if !headers.contains_key(header::USER_AGENT.as_str()) {
request = request.header(header::USER_AGENT, HeaderValue::from_static("tauri")); request = request.header(header::USER_AGENT, "tauri-plugin-http");
} }
request = request.header(header::ORIGIN, webview.url().as_str());
if let Some(data) = data { if let Some(data) = data {
request = request.body(data); request = request.body(data);
} }

@ -9,7 +9,7 @@
pub use reqwest; pub use reqwest;
use tauri::{ use tauri::{
plugin::{Builder, TauriPlugin}, plugin::{Builder, TauriPlugin},
AppHandle, Manager, Runtime, Manager, Runtime,
}; };
pub use error::{Error, Result}; pub use error::{Error, Result};
@ -18,32 +18,28 @@ mod commands;
mod error; mod error;
mod scope; mod scope;
struct Http<R: Runtime> { pub(crate) struct Http {
#[allow(dead_code)] #[cfg(feature = "cookies")]
app: AppHandle<R>, cookies_jar: std::sync::Arc<reqwest::cookie::Jar>,
} }
/* trait HttpExt<R: Runtime> {
fn http(&self) -> &Http<R>;
}
impl<R: Runtime, T: Manager<R>> HttpExt<R> for T {
fn http(&self) -> &Http<R> {
self.state::<Http<R>>().inner()
}
} */
pub fn init<R: Runtime>() -> TauriPlugin<R> { pub fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::<R>::new("http") Builder::<R>::new("http")
.setup(|app, _| {
let state = Http {
#[cfg(feature = "cookies")]
cookies_jar: std::sync::Arc::new(reqwest::cookie::Jar::default()),
};
app.manage(state);
Ok(())
})
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
commands::fetch, commands::fetch,
commands::fetch_cancel, commands::fetch_cancel,
commands::fetch_send, commands::fetch_send,
commands::fetch_read_body, commands::fetch_read_body,
]) ])
.setup(|app, _api| {
app.manage(Http { app: app.clone() });
Ok(())
})
.build() .build()
} }

Loading…
Cancel
Save