Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 58 additions & 30 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ The following items are planned in MVP:
- [x] Nyquest blocking API
- [x] Nyquest async API
- [x] Backend: WinRT HttpClient
- [x] Backend: WinHTTP
- [x] Backend: libcurl
- [x] Backend: NSURLSession
- [x] Backend: reqwest (with WASM support)
Expand All @@ -82,7 +83,6 @@ Future work may include:
- [ ] Telemetry
- [ ] Backend: Plugin FFI via libloading
- [ ] Backend: Mock
- [x] Backend: WinHTTP
- [ ] Backend: libsoup3
- [ ] Backend: QNetworkAccessManager
- [ ] Explore alternative options on Android other than libcurl
Expand Down
32 changes: 32 additions & 0 deletions backends/curl/src/curl_ng/easy/opt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use crate::curl_ng::{
CurlCodeContext, WithCurlCodeContext as _,
};

const CURLOPT_SUPPRESS_CONNECT_HEADERS: curl_sys::CURLoption = curl_sys::CURLOPTTYPE_LONG + 265;

impl RawEasy {
pub(super) unsafe fn setopt_str(
self: Pin<&mut Self>,
Expand Down Expand Up @@ -61,6 +63,36 @@ impl RawEasy {
}
}

pub fn set_proxy<'s>(
self: Pin<&mut Self>,
proxy: impl Into<Cow<'s, str>>,
) -> Result<(), CurlCodeContext> {
unsafe {
self.setopt_str(curl_sys::CURLOPT_PROXY, proxy.into())
.with_easy_context("setopt CURLOPT_PROXY")
}
}

pub fn set_http_proxy_tunnel(
self: Pin<&mut Self>,
tunnel: bool,
) -> Result<(), CurlCodeContext> {
unsafe {
self.setopt_long(curl_sys::CURLOPT_HTTPPROXYTUNNEL, tunnel as c_long)
.with_easy_context("setopt CURLOPT_HTTPPROXYTUNNEL")
}
}

pub fn set_suppress_connect_headers(
self: Pin<&mut Self>,
suppress: bool,
) -> Result<(), CurlCodeContext> {
unsafe {
self.setopt_long(CURLOPT_SUPPRESS_CONNECT_HEADERS, suppress as c_long)
.with_easy_context("setopt CURLOPT_SUPPRESS_CONNECT_HEADERS")
}
}

pub fn set_useragent<'s>(
self: Pin<&mut Self>,
user_agent: impl Into<Cow<'s, str>>,
Expand Down
24 changes: 21 additions & 3 deletions backends/curl/src/request.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::ops::{Deref, DerefMut};
use std::pin::Pin;

use nyquest_interface::client::ProxyOptions;
use nyquest_interface::{Body, Method, Request, Result as NyquestResult};

use crate::curl_ng::CurlCodeContext;
Expand Down Expand Up @@ -36,7 +37,7 @@ pub fn create_easy<C: EasyCallback>(callback: C, share: &Share) -> NyquestResult
pub fn populate_request<S, C: EasyCallback, R: MimePartReader + Send + 'static>(
url: &str,
mut req: Request<S>,
options: &nyquest_interface::client::ClientOptions,
options: &nyquest_interface::client::ClientOptions, // FIXME: strings in options are copied to be null-terminated. Can we avoid that?
easy: Pin<&mut EasyHandle<C>>,
populate_stream: impl FnOnce(Pin<&mut EasyHandle<C>>, S) -> Result<(), CurlCodeContext>,
#[cfg_attr(not(feature = "multipart"), allow(unused, unused_mut))]
Expand All @@ -45,8 +46,25 @@ pub fn populate_request<S, C: EasyCallback, R: MimePartReader + Send + 'static>(
let mut headers = CurlStringList::default();
easy.with_error_message(|mut e| {
let mut raw = e.as_mut().as_raw_easy_mut();
if !options.use_default_proxy {
raw.as_mut().set_noproxy("*")?;
match &options.proxy_options {
ProxyOptions::Default => {}
ProxyOptions::None => raw.as_mut().set_noproxy("*")?,
ProxyOptions::Custom {
proxy_url_for_http,
proxy_url_for_https,
proxy_bypass,
} => {
raw.as_mut().set_proxy(&**proxy_url_for_http)?;
if proxy_url_for_https.is_some() {
// TODO: curl doesn't have a separate option for HTTPS proxy.
raw.as_mut().set_http_proxy_tunnel(true)?;
raw.as_mut().set_suppress_connect_headers(true)?;
}
Comment on lines +57 to +62

if let Some(proxy_bypass) = proxy_bypass {
raw.as_mut().set_noproxy(&**proxy_bypass)?;
}
}
}
if let Some(user_agent) = options.user_agent.as_deref() {
raw.as_mut().set_useragent(user_agent)?;
Expand Down
3 changes: 2 additions & 1 deletion backends/nsurlsession/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ cfg-if.workspace = true
[target.'cfg(target_vendor = "apple")'.dependencies]
block2 = { version = "0.6", default-features = false }
objc2 = { version = "0.6", default-features = false }
objc2-foundation = { version = "0.3", default-features = false, features = [
objc2-foundation = { version = "0.3.2", default-features = false, features = [
"alloc",
"block2",
"NSError",
"NSObject",
"NSCharacterSet",
"NSArray",
"NSString",
"NSValue",
"NSData",
"NSDate",
"NSURL",
Expand Down
18 changes: 5 additions & 13 deletions backends/nsurlsession/src/async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ impl AsyncResponse for NSUrlSessionAsyncResponse {
.set_max_response_buffer_size(self.max_response_buffer_size);
let inner = &mut self.inner;
let inner_waker = coerce_waker(inner.shared.waker_ref());
unsafe {
inner.task.resume();
}
inner.task.resume();
poll_fn(|cx| {
if inner.shared.is_completed() {
return Poll::Ready(());
Expand All @@ -63,9 +61,7 @@ impl AsyncResponse for NSUrlSessionAsyncResponse {
})
.await;
let res = inner.shared.take_response_buffer()?;
unsafe {
inner.task.error().into_nyquest_result()?;
}
inner.task.error().into_nyquest_result()?;
Ok(res)
}
}
Expand All @@ -85,9 +81,7 @@ impl nyquest_interface::r#async::futures_io::AsyncRead for NSUrlSessionAsyncResp

let inner_waker = coerce_waker(inner.shared.waker_ref());
inner_waker.register(cx);
unsafe {
inner.task.resume();
}
inner.task.resume();
Poll::Pending
}
}
Expand Down Expand Up @@ -115,7 +109,7 @@ impl AsyncClient for NSUrlSessionAsyncClient {
unreachable!("async-stream feature is disabled")
}
})?;
let shared = unsafe {
let shared = {
let delegate = DataTaskDelegate::new(waker, self.inner.allow_redirects);
task.setDelegate(Some(ProtocolObject::from_ref(&*delegate)));
task.resume();
Expand All @@ -140,9 +134,7 @@ impl AsyncClient for NSUrlSessionAsyncClient {
Poll::Pending
})
.await?;
unsafe {
task.error().into_nyquest_result()?;
}
task.error().into_nyquest_result()?;
Ok(NSUrlSessionAsyncResponse {
inner: NSUrlSessionResponse {
task,
Expand Down
Loading
Loading