feat(tokio): add reqwest feature (#734)

Move the client ReqwestNetworkClient to ironrdp-tokio, so other clients
can optionally use the implementation.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-Andre Lureau 2025-04-02 22:59:02 +04:00 committed by GitHub
parent 817abb9805
commit 032c38be92
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 41 additions and 18 deletions

6
Cargo.lock generated
View file

@ -2432,16 +2432,13 @@ dependencies = [
"ironrdp-tokio", "ironrdp-tokio",
"proc-exit", "proc-exit",
"raw-window-handle", "raw-window-handle",
"reqwest",
"semver", "semver",
"smallvec", "smallvec",
"softbuffer", "softbuffer",
"sspi",
"tap", "tap",
"tokio", "tokio",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"url",
"uuid", "uuid",
"whoami", "whoami",
"windows 0.58.0", "windows 0.58.0",
@ -2783,7 +2780,10 @@ version = "0.3.0"
dependencies = [ dependencies = [
"bytes", "bytes",
"ironrdp-async", "ironrdp-async",
"reqwest",
"sspi",
"tokio", "tokio",
"url",
] ]
[[package]] [[package]]

View file

@ -13,6 +13,7 @@ mod session;
use core::future::Future; use core::future::Future;
use core::pin::Pin; use core::pin::Pin;
pub use ironrdp_connector;
use ironrdp_connector::sspi::generator::NetworkRequest; use ironrdp_connector::sspi::generator::NetworkRequest;
use ironrdp_connector::ConnectorResult; use ironrdp_connector::ConnectorResult;

View file

@ -40,14 +40,17 @@ ironrdp = { path = "../ironrdp", version = "0.9", features = [
"rdpsnd", "rdpsnd",
"cliprdr", "cliprdr",
"displaycontrol", "displaycontrol",
"connector" "connector",
] }
ironrdp-core = { path = "../ironrdp-core", version = "0.1", features = [
"alloc",
] } ] }
ironrdp-core = { path = "../ironrdp-core", version = "0.1", features = ["alloc"] }
ironrdp-cliprdr-native = { path = "../ironrdp-cliprdr-native", version = "0.2" } ironrdp-cliprdr-native = { path = "../ironrdp-cliprdr-native", version = "0.2" }
ironrdp-rdpsnd-native = { path = "../ironrdp-rdpsnd-native", version = "0.2" } ironrdp-rdpsnd-native = { path = "../ironrdp-rdpsnd-native", version = "0.2" }
ironrdp-tls = { path = "../ironrdp-tls", version = "0.1" } ironrdp-tls = { path = "../ironrdp-tls", version = "0.1" }
ironrdp-tokio = { path = "../ironrdp-tokio", version = "0.3" } ironrdp-tokio = { path = "../ironrdp-tokio", version = "0.3", features = [
sspi = { version = "0.15", features = ["network_client", "dns_resolver"] } # TODO: enable additional features "reqwest",
] }
# Windowing and rendering # Windowing and rendering
winit = { version = "0.30", features = ["rwh_06"] } winit = { version = "0.30", features = ["rwh_06"] }
@ -71,8 +74,6 @@ anyhow = "1"
smallvec = "1.13" smallvec = "1.13"
tap = "1" tap = "1"
semver = "1" semver = "1"
reqwest = "0.12"
url = "2.5"
raw-window-handle = "0.6" raw-window-handle = "0.6"
uuid = { version = "1.16" } uuid = { version = "1.16" }

View file

@ -15,5 +15,4 @@ extern crate tracing;
pub mod app; pub mod app;
pub mod clipboard; pub mod clipboard;
pub mod config; pub mod config;
pub mod network_client;
pub mod rdp; pub mod rdp;

View file

@ -10,6 +10,7 @@ use ironrdp::session::{fast_path, ActiveStage, ActiveStageOutput, GracefulDiscon
use ironrdp::{cliprdr, connector, rdpdr, rdpsnd, session}; use ironrdp::{cliprdr, connector, rdpdr, rdpsnd, session};
use ironrdp_core::WriteBuf; use ironrdp_core::WriteBuf;
use ironrdp_rdpsnd_native::cpal; use ironrdp_rdpsnd_native::cpal;
use ironrdp_tokio::reqwest::ReqwestNetworkClient;
use ironrdp_tokio::{single_sequence_step_read, split_tokio_framed, FramedWrite}; use ironrdp_tokio::{single_sequence_step_read, split_tokio_framed, FramedWrite};
use rdpdr::NoopRdpdrBackend; use rdpdr::NoopRdpdrBackend;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -146,7 +147,7 @@ async fn connect(
let mut upgraded_framed = ironrdp_tokio::TokioFramed::new(upgraded_stream); let mut upgraded_framed = ironrdp_tokio::TokioFramed::new(upgraded_stream);
let mut network_client = crate::network_client::ReqwestNetworkClient::new(); let mut network_client = ReqwestNetworkClient::new();
let connection_result = ironrdp_tokio::connect_finalize( let connection_result = ironrdp_tokio::connect_finalize(
upgraded, upgraded,
&mut upgraded_framed, &mut upgraded_framed,

View file

@ -15,11 +15,20 @@ categories.workspace = true
doctest = false doctest = false
test = false test = false
[features]
default = ["reqwest"]
reqwest = ["dep:reqwest", "dep:sspi", "dep:url"]
[dependencies] [dependencies]
bytes = "1" bytes = "1"
ironrdp-async = { path = "../ironrdp-async", version = "0.4" } # public ironrdp-async = { path = "../ironrdp-async", version = "0.4" } # public
tokio = { version = "1", features = ["io-util"] } tokio = { version = "1", features = ["io-util"] }
reqwest = { version = "0.12", optional = true }
sspi = { version = "0.15", features = [
"network_client",
"dns_resolver",
], optional = true } # TODO: enable additional features
url = { version = "2.5", optional = true }
[lints] [lints]
workspace = true workspace = true

View file

@ -4,6 +4,9 @@
#[rustfmt::skip] // do not re-order this pub use #[rustfmt::skip] // do not re-order this pub use
pub use ironrdp_async::*; pub use ironrdp_async::*;
#[cfg(feature = "reqwest")]
pub mod reqwest;
use core::pin::Pin; use core::pin::Pin;
use std::io; use std::io;

View file

@ -2,15 +2,16 @@ use core::future::Future;
use core::pin::Pin; use core::pin::Pin;
use std::net::{IpAddr, Ipv4Addr}; use std::net::{IpAddr, Ipv4Addr};
use ironrdp::connector::{custom_err, ConnectorResult}; use ironrdp_async::ironrdp_connector::{custom_err, ConnectorResult};
use ironrdp_tokio::AsyncNetworkClient;
use reqwest::Client; use reqwest::Client;
use sspi::{Error, ErrorKind}; use sspi::{Error, ErrorKind};
use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpStream, UdpSocket}; use tokio::net::{TcpStream, UdpSocket};
use url::Url; use url::Url;
pub(crate) struct ReqwestNetworkClient { use crate::AsyncNetworkClient;
pub struct ReqwestNetworkClient {
client: Option<Client>, client: Option<Client>,
} }
@ -32,11 +33,17 @@ impl AsyncNetworkClient for ReqwestNetworkClient {
} }
impl ReqwestNetworkClient { impl ReqwestNetworkClient {
pub(crate) fn new() -> Self { pub fn new() -> Self {
Self { client: None } Self { client: None }
} }
} }
impl Default for ReqwestNetworkClient {
fn default() -> Self {
Self::new()
}
}
impl ReqwestNetworkClient { impl ReqwestNetworkClient {
async fn send_tcp(&self, url: &Url, data: &[u8]) -> ConnectorResult<Vec<u8>> { async fn send_tcp(&self, url: &Url, data: &[u8]) -> ConnectorResult<Vec<u8>> {
let addr = format!("{}:{}", url.host_str().unwrap_or_default(), url.port().unwrap_or(88)); let addr = format!("{}:{}", url.host_str().unwrap_or_default(), url.port().unwrap_or(88));
@ -89,10 +96,12 @@ impl ReqwestNetworkClient {
.recv(&mut buf) .recv(&mut buf)
.await .await
.map_err(|e| custom_err!("failed to receive UDP request", e))?; .map_err(|e| custom_err!("failed to receive UDP request", e))?;
let buf = &buf[0..n];
let mut reply_buf = Vec::with_capacity(n + 4); let mut reply_buf = Vec::with_capacity(n + 4);
reply_buf.extend_from_slice(&(n as u32).to_be_bytes()); let n = u32::try_from(n).map_err(|e| custom_err!("invalid length", e))?;
reply_buf.extend_from_slice(&buf[0..n]); reply_buf.extend_from_slice(&n.to_be_bytes());
reply_buf.extend_from_slice(buf);
Ok(reply_buf) Ok(reply_buf)
} }