Skip to content
Open
Show file tree
Hide file tree
Changes from 9 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