Skip to content
Open
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
2 changes: 2 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ wreq = { version = "6.0.0-rc.28", features = [
] }
wreq-util = "3.0.0-rc.11"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = { version = "1.0", features = ["preserve_order"] }
serde_magnus = "0.11.0"
indexmap = { version = "2.14.0", features = ["serde"] }
cookie = "0.18.1"
Expand Down
21 changes: 21 additions & 0 deletions lib/wreq_ruby/emulation.rb → lib/wreq_ruby/emulate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class EmulationDevice
Chrome145 = nil
Chrome146 = nil
Chrome147 = nil

Edge101 = nil
Edge122 = nil
Edge127 = nil
Expand All @@ -70,6 +71,7 @@ class EmulationDevice
Edge145 = nil
Edge146 = nil
Edge147 = nil

Firefox109 = nil
Firefox117 = nil
Firefox128 = nil
Expand All @@ -88,6 +90,7 @@ class EmulationDevice
Firefox147 = nil
Firefox148 = nil
Firefox149 = nil

SafariIos17_2 = nil
SafariIos17_4_1 = nil
SafariIos16_5 = nil
Expand Down Expand Up @@ -115,6 +118,7 @@ class EmulationDevice
SafariIos26_2 = nil
SafariIPad26 = nil
SafariIpad26_2 = nil

OkHttp3_9 = nil
OkHttp3_11 = nil
OkHttp3_13 = nil
Expand All @@ -123,6 +127,7 @@ class EmulationDevice
OkHttp4_10 = nil
OkHttp4_12 = nil
OkHttp5 = nil

Opera116 = nil
Opera117 = nil
Opera118 = nil
Expand Down Expand Up @@ -199,5 +204,21 @@ class Emulation
def self.new(device: nil, os: nil, skip_http2: false, skip_headers: false)
end
end

unless method_defined?(:parse)
# Parses a string representation of an emulation option.
# @param json [String] String to parse into an TLS/HTTP2 emulation option
# @param permute_extensions [Boolean, nil] Whether to permute extensions (optional)
# @param psk_skip_session_ticket [Boolean] Whether to skip session ticket for PSK
# @param aes_hw_override [Boolean, nil] Override AES hardware support (optional)
# @param random_aes_hw_override [Boolean] Whether to randomly override AES
# @return [Wreq::Emulation] Parsed emulation option
def self.parse(json,
permute_extensions: nil,
psk_skip_session_ticket: false,
aes_hw_override: nil,
random_aes_hw_override: false)
end
end
end
end
60 changes: 35 additions & 25 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ use crate::{
http::Method,
};

macro_rules! request {
($args:expr, $required:ty) => {{
let args = magnus::scan_args::scan_args::<$required, (), (), (), magnus::RHash, ()>($args)?;
let required = args.required;
let request = crate::client::req::Request::new(&ruby!(), args.keywords)?;
(required, request)
}};
}

/// A builder for `Client`.
#[derive(Default, Deserialize)]
struct Builder {
Expand Down Expand Up @@ -127,31 +136,32 @@ pub struct Client(wreq::Client);

impl Builder {
/// Create a new [`Builder`] from Ruby keyword arguments.
fn new(ruby: &magnus::Ruby, keyword: &Value) -> Result<Self, magnus::Error> {
if let Ok(hash) = RHash::try_convert(*keyword) {
fn new(ruby: &magnus::Ruby, keyword: Value) -> Result<Self, magnus::Error> {
if let Ok(hash) = RHash::try_convert(keyword) {
let mut builder: Self = serde_magnus::deserialize(ruby, hash)?;
// extra emulation handling
if let Some(v) = hash.get(ruby.to_symbol("emulation")) {
let emulation_obj = Obj::<Emulation>::try_convert(v)?;
builder.emulation = Some((*emulation_obj).clone());
if let Some(v) = hash.get(ruby.to_symbol(stringify!(emulation))) {
let obj = Obj::<Emulation>::try_convert(v)?;
builder.emulation = Some((*obj).clone());
}

// extra cookie store handling
if let Some(jar) = hash.get(ruby.to_symbol(stringify!(cookie_provider))) {
let obj = Obj::<Jar>::try_convert(jar)?;
builder.cookie_provider = Some((*obj).clone());
}

// extra user agent handling
builder.user_agent = Extractor::<HeaderValue>::try_convert(*keyword)?.into_inner();
builder.user_agent = Extractor::<HeaderValue>::try_convert(keyword)?.into_inner();

// extra headers handling
builder.headers = Extractor::<HeaderMap>::try_convert(*keyword)?.into_inner();
builder.headers = Extractor::<HeaderMap>::try_convert(keyword)?.into_inner();

// extra original headers handling
builder.orig_headers = Extractor::<OrigHeaderMap>::try_convert(*keyword)?.into_inner();
builder.orig_headers = Extractor::<OrigHeaderMap>::try_convert(keyword)?.into_inner();

// extra proxy handling
builder.proxy = Extractor::<Proxy>::try_convert(*keyword)?.into_inner();

// extra cookie store handling
if let Some(jar) = hash.get(ruby.to_symbol("cookie_provider")) {
builder.cookie_provider = Some((*Obj::<Jar>::try_convert(jar)?).clone());
}
builder.proxy = Extractor::<Proxy>::try_convert(keyword)?.into_inner();

return Ok(builder);
}
Expand All @@ -166,12 +176,12 @@ impl Client {
/// Create a new [`Client`] with the given keyword arguments.
pub fn new(ruby: &Ruby, kwargs: &[Value]) -> Result<Self, magnus::Error> {
if let Some(kwargs) = kwargs.first() {
let mut params = Builder::new(ruby, kwargs)?;
let mut params = Builder::new(ruby, *kwargs)?;
gvl::nogvl(|| {
let mut builder = wreq::Client::builder();

// Emulation options.
apply_option!(set_if_some_inner, builder, params.emulation, emulation);
apply_option!(set_if_some, builder, params.emulation, emulation);

// User agent options.
apply_option!(set_if_some, builder, params.user_agent, user_agent);
Expand Down Expand Up @@ -312,63 +322,63 @@ impl Client {
/// Send a HTTP request.
#[inline]
pub fn request(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
let ((method, url), request) = extract_request!(args, (Obj<Method>, String));
let ((method, url), request) = request!(args, (Obj<Method>, String));
execute_request(rb_self.0.clone(), *method, url, request)
}

/// Send a GET request.
#[inline]
pub fn get(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
let ((url,), request) = extract_request!(args, (String,));
let ((url,), request) = request!(args, (String,));
execute_request(rb_self.0.clone(), Method::GET, url, request)
}

/// Send a POST request.
#[inline]
pub fn post(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
let ((url,), request) = extract_request!(args, (String,));
let ((url,), request) = request!(args, (String,));
execute_request(rb_self.0.clone(), Method::POST, url, request)
}

/// Send a PUT request.
#[inline]
pub fn put(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
let ((url,), request) = extract_request!(args, (String,));
let ((url,), request) = request!(args, (String,));
execute_request(rb_self.0.clone(), Method::PUT, url, request)
}

/// Send a DELETE request.
#[inline]
pub fn delete(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
let ((url,), request) = extract_request!(args, (String,));
let ((url,), request) = request!(args, (String,));
execute_request(rb_self.0.clone(), Method::DELETE, url, request)
}

/// Send a HEAD request.
#[inline]
pub fn head(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
let ((url,), request) = extract_request!(args, (String,));
let ((url,), request) = request!(args, (String,));
execute_request(rb_self.0.clone(), Method::HEAD, url, request)
}

/// Send an OPTIONS request.
#[inline]
pub fn options(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
let ((url,), request) = extract_request!(args, (String,));
let ((url,), request) = request!(args, (String,));
execute_request(rb_self.0.clone(), Method::OPTIONS, url, request)
}

/// Send a TRACE request.
#[inline]
pub fn trace(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
let ((url,), request) = extract_request!(args, (String,));
let ((url,), request) = request!(args, (String,));
execute_request(rb_self.0.clone(), Method::TRACE, url, request)
}

/// Send a PATCH request.
#[inline]
pub fn patch(rb_self: &Self, args: &[Value]) -> Result<Response, magnus::Error> {
let ((url,), request) = extract_request!(args, (String,));
let ((url,), request) = request!(args, (String,));
execute_request(rb_self.0.clone(), Method::PATCH, url, request)
}
}
Expand Down
18 changes: 9 additions & 9 deletions src/client/req.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,14 @@ impl Request {
let mut builder: Self = serde_magnus::deserialize(ruby, kwargs)?;

// extra emulation handling
if let Some(v) = hash.get(ruby.to_symbol("emulation")) {
let emulation_obj = Obj::<Emulation>::try_convert(v)?;
builder.emulation = Some((*emulation_obj).clone());
if let Some(v) = hash.get(ruby.to_symbol(stringify!(emulation))) {
let obj = Obj::<Emulation>::try_convert(v)?;
builder.emulation = Some((*obj).clone());
}

// extra body handling
if let Some(body) = hash.get(ruby.to_symbol(stringify!(body))) {
builder.body = Some(Body::try_convert(body)?);
}

// extra version handling
Expand All @@ -129,11 +134,6 @@ impl Request {
// extra proxy handling
builder.proxy = Extractor::<Proxy>::try_convert(kwargs)?.into_inner();

// extra body handling
if let Some(body) = hash.get(ruby.to_symbol("body")) {
builder.body = Some(Body::try_convert(body)?);
}

Ok(builder)
}
}
Expand All @@ -148,7 +148,7 @@ pub fn execute_request<U: AsRef<str>>(
let mut builder = client.request(method.into_ffi(), url.as_ref());

// Emulation options.
apply_option!(set_if_some_inner, builder, request.emulation, emulation);
apply_option!(set_if_some, builder, request.emulation, emulation);

// Version options.
apply_option!(set_if_some, builder, request.version, version);
Expand Down
Loading