frontend-utils: Switch to reqwest
This commit is contained in:
parent
b1a8ed455f
commit
7079f38a9f
File diff suppressed because it is too large
Load Diff
|
@ -71,6 +71,7 @@ thiserror = "1.0"
|
|||
url = "2.5.0"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
walkdir = "2.5.0"
|
||||
tokio = { version = "1.37.0" }
|
||||
|
||||
[workspace.lints.rust]
|
||||
# Clippy nightly often adds new/buggy lints that we want to ignore.
|
||||
|
|
|
@ -43,6 +43,7 @@ chrono = { workspace = true }
|
|||
fluent-templates = "0.9.1"
|
||||
toml_edit = { version = "0.22.9", features = ["parse"] }
|
||||
gilrs = "0.10"
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "macros"]}
|
||||
|
||||
# Deliberately held back to match tracy client used by profiling crate
|
||||
tracing-tracy = { version = "=0.10.4", optional = true }
|
||||
|
|
|
@ -146,7 +146,8 @@ fn shutdown() {
|
|||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Error> {
|
||||
init();
|
||||
|
||||
let opt = Opt::parse();
|
||||
|
|
|
@ -20,12 +20,12 @@ urlencoding = "2.1.3"
|
|||
ruffle_core = { path = "../core", default-features = false }
|
||||
async-channel = { workspace = true }
|
||||
slotmap = { workspace = true }
|
||||
isahc = { version = "1.7.2", features = ["cookies"] }
|
||||
futures = { workspace = true }
|
||||
async-io = "2.3.2"
|
||||
async-net = "2.0.0"
|
||||
futures-lite = "2.3.0"
|
||||
webbrowser = "0.8.14"
|
||||
reqwest = { version = "0.12.3", features = ["cookies"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3"
|
||||
|
|
|
@ -9,9 +9,7 @@ use async_net::TcpStream;
|
|||
use futures::future::select;
|
||||
use futures::{AsyncReadExt, AsyncWriteExt};
|
||||
use futures_lite::FutureExt;
|
||||
use isahc::config::{Configurable, RedirectPolicy};
|
||||
use isahc::http::{HeaderName, HeaderValue};
|
||||
use isahc::{HttpClient, Request as IsahcRequest, ResponseExt};
|
||||
use reqwest::Proxy;
|
||||
use ruffle_core::backend::navigator::{
|
||||
async_return, create_fetch_error, ErrorResponse, NavigationMethod, NavigatorBackend,
|
||||
OpenURLMode, OwnedFuture, Request, SocketMode, SuccessResponse,
|
||||
|
@ -25,7 +23,6 @@ use std::io;
|
|||
use std::io::ErrorKind;
|
||||
use std::path::Path;
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
use tracing::warn;
|
||||
|
@ -53,7 +50,7 @@ pub struct ExternalNavigatorBackend<F: FutureSpawner, I: NavigatorInterface> {
|
|||
base_url: Url,
|
||||
|
||||
// Client to use for network requests
|
||||
client: Option<Rc<HttpClient>>,
|
||||
client: Option<Rc<reqwest::Client>>,
|
||||
|
||||
socket_allowed: HashSet<String>,
|
||||
|
||||
|
@ -82,11 +79,18 @@ impl<F: FutureSpawner, I: NavigatorInterface> ExternalNavigatorBackend<F, I> {
|
|||
content: Rc<PlayingContent>,
|
||||
interface: I,
|
||||
) -> Self {
|
||||
let proxy = proxy.and_then(|url| url.as_str().parse().ok());
|
||||
let builder = HttpClient::builder()
|
||||
.proxy(proxy)
|
||||
.cookies()
|
||||
.redirect_policy(RedirectPolicy::Follow);
|
||||
let mut builder = reqwest::ClientBuilder::new().cookie_store(true);
|
||||
|
||||
if let Some(proxy) = proxy {
|
||||
match Proxy::all(proxy.clone()) {
|
||||
Ok(proxy) => {
|
||||
builder = builder.proxy(proxy);
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Couldn't configure proxy {proxy}: {e}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let client = builder.build().ok().map(Rc::new);
|
||||
|
||||
|
@ -221,44 +225,23 @@ impl<F: FutureSpawner, I: NavigatorInterface> NavigatorBackend for ExternalNavig
|
|||
error: Error::FetchError("Network unavailable".to_string()),
|
||||
})?;
|
||||
|
||||
let mut isahc_request = match request.method() {
|
||||
NavigationMethod::Get => IsahcRequest::get(processed_url.to_string()),
|
||||
NavigationMethod::Post => IsahcRequest::post(processed_url.to_string()),
|
||||
let mut request_builder = match request.method() {
|
||||
NavigationMethod::Get => client.get(processed_url.clone()),
|
||||
NavigationMethod::Post => client.post(processed_url.clone()),
|
||||
};
|
||||
let (body_data, mime) = request.body().clone().unwrap_or_default();
|
||||
if let Some(headers) = isahc_request.headers_mut() {
|
||||
for (name, val) in request.headers().iter() {
|
||||
headers.insert(
|
||||
HeaderName::from_str(name).map_err(|e| ErrorResponse {
|
||||
url: processed_url.to_string(),
|
||||
error: Error::FetchError(e.to_string()),
|
||||
})?,
|
||||
HeaderValue::from_str(val).map_err(|e| ErrorResponse {
|
||||
url: processed_url.to_string(),
|
||||
error: Error::FetchError(e.to_string()),
|
||||
})?,
|
||||
);
|
||||
}
|
||||
headers.insert(
|
||||
"Content-Type",
|
||||
HeaderValue::from_str(&mime).map_err(|e| ErrorResponse {
|
||||
url: processed_url.to_string(),
|
||||
error: Error::FetchError(e.to_string()),
|
||||
})?,
|
||||
);
|
||||
for (name, val) in request.headers().iter() {
|
||||
request_builder = request_builder.header(name, val);
|
||||
}
|
||||
request_builder = request_builder.header("Content-Type", &mime);
|
||||
|
||||
let body = isahc_request.body(body_data).map_err(|e| ErrorResponse {
|
||||
url: processed_url.to_string(),
|
||||
error: Error::FetchError(e.to_string()),
|
||||
})?;
|
||||
request_builder = request_builder.body(body_data);
|
||||
|
||||
let response = client.send_async(body).await.map_err(|e| {
|
||||
let inner = match e.kind() {
|
||||
isahc::error::ErrorKind::NameResolution => {
|
||||
Error::InvalidDomain(processed_url.to_string())
|
||||
}
|
||||
_ => Error::FetchError(e.to_string()),
|
||||
let response = request_builder.send().await.map_err(|e| {
|
||||
let inner = if e.is_connect() {
|
||||
Error::InvalidDomain(processed_url.to_string())
|
||||
} else {
|
||||
Error::FetchError(e.to_string())
|
||||
};
|
||||
ErrorResponse {
|
||||
url: processed_url.to_string(),
|
||||
|
@ -266,27 +249,23 @@ impl<F: FutureSpawner, I: NavigatorInterface> NavigatorBackend for ExternalNavig
|
|||
}
|
||||
})?;
|
||||
|
||||
let url = if let Some(uri) = response.effective_uri() {
|
||||
uri.to_string()
|
||||
} else {
|
||||
processed_url.into()
|
||||
};
|
||||
let url = response.url().to_string();
|
||||
|
||||
let status = response.status().as_u16();
|
||||
let redirected = response.effective_uri().is_some();
|
||||
let redirected = *response.url() != processed_url;
|
||||
if !response.status().is_success() {
|
||||
let error = Error::HttpNotOk(
|
||||
format!("HTTP status is not ok, got {}", response.status()),
|
||||
status,
|
||||
redirected,
|
||||
response.body().len().unwrap_or(0),
|
||||
response.content_length().unwrap_or_default(),
|
||||
);
|
||||
return Err(ErrorResponse { url, error });
|
||||
}
|
||||
|
||||
let response: Box<dyn SuccessResponse> = Box::new(Response {
|
||||
url,
|
||||
response_body: ResponseBody::Network(Arc::new(Mutex::new(response))),
|
||||
response_body: ResponseBody::Network(Arc::new(Mutex::new(Some(response)))),
|
||||
status,
|
||||
redirected,
|
||||
});
|
||||
|
@ -484,6 +463,7 @@ mod tests {
|
|||
use async_net::TcpListener;
|
||||
use ruffle_core::socket::SocketAction::{Close, Connect, Data};
|
||||
use std::net::SocketAddr;
|
||||
use std::str::FromStr;
|
||||
use tokio::task;
|
||||
|
||||
use super::*;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use futures::AsyncReadExt;
|
||||
use isahc::{prelude::*, AsyncBody, Response as IsahcResponse};
|
||||
use reqwest::Response as ReqwestResponse;
|
||||
use ruffle_core::backend::navigator::{OwnedFuture, SuccessResponse};
|
||||
use ruffle_core::loader::Error;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
@ -13,7 +12,7 @@ pub enum ResponseBody {
|
|||
/// This has to be stored in shared ownership so that we can return
|
||||
/// owned futures. A synchronous lock is used here as we do not
|
||||
/// expect contention on this lock.
|
||||
Network(Arc<Mutex<IsahcResponse<AsyncBody>>>),
|
||||
Network(Arc<Mutex<Option<ReqwestResponse>>>),
|
||||
}
|
||||
|
||||
pub struct Response {
|
||||
|
@ -35,15 +34,15 @@ impl SuccessResponse for Response {
|
|||
Box::pin(async move { file.map_err(|e| Error::FetchError(e.to_string())) })
|
||||
}
|
||||
ResponseBody::Network(response) => Box::pin(async move {
|
||||
let mut body = vec![];
|
||||
response
|
||||
Ok(response
|
||||
.lock()
|
||||
.expect("working lock during fetch body read")
|
||||
.copy_to(&mut body)
|
||||
.take()
|
||||
.expect("Body cannot already be consumed")
|
||||
.bytes()
|
||||
.await
|
||||
.map_err(|e| Error::FetchError(e.to_string()))?;
|
||||
|
||||
Ok(body)
|
||||
.map_err(|e| Error::FetchError(e.to_string()))?
|
||||
.to_vec())
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -75,9 +74,7 @@ impl SuccessResponse for Response {
|
|||
}
|
||||
ResponseBody::Network(response) => {
|
||||
let response = response.clone();
|
||||
|
||||
Box::pin(async move {
|
||||
let mut buf = vec![0; 4096];
|
||||
let lock = response.try_lock();
|
||||
if matches!(lock, Err(std::sync::TryLockError::WouldBlock)) {
|
||||
return Err(Error::FetchError(
|
||||
|
@ -88,16 +85,14 @@ impl SuccessResponse for Response {
|
|||
|
||||
let result = lock
|
||||
.expect("desktop network lock")
|
||||
.body_mut()
|
||||
.read(&mut buf)
|
||||
.as_mut()
|
||||
.expect("Body cannot already be consumed")
|
||||
.chunk()
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(count) if count > 0 => {
|
||||
buf.resize(count, 0);
|
||||
Ok(Some(buf))
|
||||
}
|
||||
Ok(_) => Ok(None),
|
||||
Ok(Some(bytes)) => Ok(Some(bytes.to_vec())),
|
||||
Ok(None) => Ok(None),
|
||||
Err(e) => Err(Error::FetchError(e.to_string())),
|
||||
}
|
||||
})
|
||||
|
@ -109,18 +104,9 @@ impl SuccessResponse for Response {
|
|||
match &self.response_body {
|
||||
ResponseBody::File(file) => Ok(file.as_ref().map(|file| file.len() as u64).ok()),
|
||||
ResponseBody::Network(response) => {
|
||||
let response = response.lock().expect("no recursive locks");
|
||||
let content_length = response.headers().get("Content-Length");
|
||||
|
||||
if let Some(len) = content_length {
|
||||
Ok(Some(
|
||||
len.to_str()
|
||||
.map_err(|_| Error::InvalidHeaderValue)?
|
||||
.parse::<u64>()?,
|
||||
))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
let lock = response.lock().expect("no recursive locks");
|
||||
let response = lock.as_ref().expect("Body cannot already be consumed");
|
||||
Ok(response.content_length())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue