wreq 1.2.5 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Cargo.lock +20 -13
- data/Cargo.toml +10 -2
- data/crates/wreq-util/src/emulate/macros.rs +12 -10
- data/crates/wreq-util/src/emulate/profile/chrome/header.rs +18 -3
- data/crates/wreq-util/src/emulate/profile/firefox/header.rs +16 -0
- data/crates/wreq-util/src/emulate/profile/opera/header.rs +6 -7
- data/crates/wreq-util/tests/client.rs +103 -1
- data/lib/wreq.rb +70 -45
- data/lib/wreq_ruby/body.rb +29 -11
- data/lib/wreq_ruby/client.rb +88 -55
- data/lib/wreq_ruby/cookie.rb +79 -19
- data/lib/wreq_ruby/emulate.rb +74 -6
- data/lib/wreq_ruby/error.rb +5 -7
- data/lib/wreq_ruby/http.rb +74 -0
- data/lib/wreq_ruby/response.rb +3 -0
- data/script/build_windows_gnu.ps1 +6 -0
- data/src/arch.rs +22 -0
- data/src/client/body/form.rs +2 -0
- data/src/client/body/json.rs +47 -14
- data/src/client/body/stream.rs +147 -43
- data/src/client/body.rs +11 -15
- data/src/client/param.rs +7 -7
- data/src/client/req.rs +87 -47
- data/src/client/resp.rs +23 -24
- data/src/client.rs +310 -230
- data/src/cookie.rs +280 -87
- data/src/emulate.rs +85 -50
- data/src/error.rs +198 -41
- data/src/extractor.rs +16 -76
- data/src/header.rs +146 -23
- data/src/http.rs +62 -33
- data/src/lib.rs +26 -20
- data/src/macros.rs +71 -46
- data/src/options.rs +284 -0
- data/src/rt.rs +22 -11
- data/src/serde/de/array_deserializer.rs +48 -0
- data/src/serde/de/array_enumerator.rs +59 -0
- data/src/serde/de/deserializer.rs +307 -0
- data/src/serde/de/enum_deserializer.rs +47 -0
- data/src/serde/de/hash_deserializer.rs +89 -0
- data/src/serde/de/number_deserializer.rs +51 -0
- data/src/serde/de/variant_deserializer.rs +101 -0
- data/src/serde/de.rs +33 -0
- data/src/serde/error.rs +146 -0
- data/src/serde/ser/enums.rs +14 -0
- data/src/serde/ser/map_serializer.rs +56 -0
- data/src/serde/ser/seq_serializer.rs +71 -0
- data/src/serde/ser/serializer.rs +194 -0
- data/src/serde/ser/struct_serializer.rs +106 -0
- data/src/serde/ser/struct_variant_serializer.rs +44 -0
- data/src/serde/ser/tuple_variant_serializer.rs +41 -0
- data/src/serde/ser.rs +18 -0
- data/src/serde/tests.rs +237 -0
- data/src/serde.rs +202 -0
- data/test/body_sender_test.rb +246 -0
- data/test/cookie_test.rb +211 -10
- data/test/json_precision_test.rb +209 -0
- data/test/option_validation_test.rb +311 -0
- data/test/value_semantics_test.rb +238 -0
- metadata +25 -2
- data/src/header/helper.rs +0 -112
data/src/emulate.rs
CHANGED
|
@@ -1,11 +1,47 @@
|
|
|
1
|
-
use
|
|
2
|
-
|
|
3
|
-
typed_data::{Inspect, Obj},
|
|
4
|
-
};
|
|
1
|
+
use ::serde::Deserialize;
|
|
2
|
+
use magnus::{Error, Module, Object, RModule, Ruby, Value, function, method, typed_data::Obj};
|
|
5
3
|
|
|
4
|
+
use crate::options::{NativeOption, Options};
|
|
5
|
+
|
|
6
|
+
/// Keyword arguments accepted by `Wreq::Emulation.new`.
|
|
7
|
+
#[derive(Default, Deserialize)]
|
|
8
|
+
struct Builder {
|
|
9
|
+
/// The browser profile to emulate.
|
|
10
|
+
#[serde(default)]
|
|
11
|
+
profile: NativeOption<Obj<Profile>>,
|
|
12
|
+
|
|
13
|
+
/// The operating-system profile to emulate.
|
|
14
|
+
#[serde(default)]
|
|
15
|
+
platform: NativeOption<Obj<Platform>>,
|
|
16
|
+
|
|
17
|
+
/// Whether HTTP/2 settings are emulated.
|
|
18
|
+
http2: Option<bool>,
|
|
19
|
+
|
|
20
|
+
/// Whether browser headers are emulated.
|
|
21
|
+
headers: Option<bool>,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ===== impl Builder =====
|
|
25
|
+
|
|
26
|
+
impl Builder {
|
|
27
|
+
/// Deserialize and convert one validated emulation options Hash.
|
|
28
|
+
///
|
|
29
|
+
/// # Errors
|
|
30
|
+
///
|
|
31
|
+
/// Returns `ArgumentError` for unknown or duplicate options and `TypeError`
|
|
32
|
+
/// for invalid option values.
|
|
33
|
+
fn from_options(options: Options<'_>) -> Result<Self, Error> {
|
|
34
|
+
let mut builder = options.validate_keys::<Self>()?.deserialize::<Self>()?;
|
|
35
|
+
extract_native_option!(options, builder, profile);
|
|
36
|
+
extract_native_option!(options, builder, platform);
|
|
37
|
+
Ok(builder)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Defines constant registration, `into_ffi`/`from_ffi`, and handlers for
|
|
42
|
+
// Ruby's `to_s`, `==`, `eql?`, and `hash` methods.
|
|
6
43
|
define_ruby_enum!(
|
|
7
44
|
/// An emulation profile.
|
|
8
|
-
const,
|
|
9
45
|
Profile,
|
|
10
46
|
"Wreq::Profile",
|
|
11
47
|
wreq_util::Profile,
|
|
@@ -150,17 +186,19 @@ define_ruby_enum!(
|
|
|
150
186
|
Opera131,
|
|
151
187
|
);
|
|
152
188
|
|
|
189
|
+
// Defines constant registration, `into_ffi`/`from_ffi`, and handlers for
|
|
190
|
+
// Ruby's `to_s`, `to_sym`, `==`, `eql?`, and `hash` methods.
|
|
153
191
|
define_ruby_enum!(
|
|
154
192
|
/// An emulation profile for OS.
|
|
155
|
-
const,
|
|
156
193
|
Platform,
|
|
157
194
|
"Wreq::Platform",
|
|
158
195
|
wreq_util::Platform,
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
196
|
+
symbols:
|
|
197
|
+
Windows => "windows",
|
|
198
|
+
MacOS => "macos",
|
|
199
|
+
Linux => "linux",
|
|
200
|
+
Android => "android",
|
|
201
|
+
IOS => "ios",
|
|
164
202
|
);
|
|
165
203
|
|
|
166
204
|
/// A struct to represent the `EmulationOption` class.
|
|
@@ -168,51 +206,41 @@ define_ruby_enum!(
|
|
|
168
206
|
#[magnus::wrap(class = "Wreq::Emulation", free_immediately, size)]
|
|
169
207
|
pub struct Emulation(pub wreq_util::Emulation);
|
|
170
208
|
|
|
171
|
-
// ===== impl Profile =====
|
|
172
|
-
|
|
173
|
-
impl Profile {
|
|
174
|
-
pub fn to_s(&self) -> String {
|
|
175
|
-
self.into_ffi().inspect()
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// ===== impl Platform =====
|
|
180
|
-
|
|
181
|
-
impl Platform {
|
|
182
|
-
pub fn to_s(&self) -> String {
|
|
183
|
-
self.into_ffi().inspect()
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
209
|
// ===== impl Emulation =====
|
|
188
210
|
|
|
189
211
|
impl Emulation {
|
|
212
|
+
/// Create emulation settings from one optional Hash.
|
|
213
|
+
///
|
|
214
|
+
/// Unknown keys, non-Hash arguments, and extra positional arguments are
|
|
215
|
+
/// rejected before the native emulation value is built.
|
|
216
|
+
///
|
|
217
|
+
/// # Errors
|
|
218
|
+
///
|
|
219
|
+
/// Returns `ArgumentError` for unknown keys or argument count and
|
|
220
|
+
/// `TypeError` for invalid option values.
|
|
190
221
|
fn new(ruby: &Ruby, args: &[Value]) -> Result<Self, Error> {
|
|
191
|
-
let mut
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if let Some(hash) = args.first().and_then(|v| RHash::from_value(*v)) {
|
|
197
|
-
if let Some(v) = hash.get(ruby.to_symbol(stringify!(profile))) {
|
|
198
|
-
profile = Some(Obj::<Profile>::try_convert(v)?);
|
|
199
|
-
}
|
|
200
|
-
if let Some(v) = hash.get(ruby.to_symbol(stringify!(platform))) {
|
|
201
|
-
platform = Some(Obj::<Platform>::try_convert(v)?);
|
|
202
|
-
}
|
|
203
|
-
if let Some(v) = hash.get(ruby.to_symbol(stringify!(http2))) {
|
|
204
|
-
http2 = Some(bool::try_convert(v)?);
|
|
205
|
-
}
|
|
206
|
-
if let Some(v) = hash.get(ruby.to_symbol(stringify!(headers))) {
|
|
207
|
-
headers = Some(bool::try_convert(v)?);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
222
|
+
let mut params = Options::from_args(ruby, args, "emulation")?
|
|
223
|
+
.map(Builder::from_options)
|
|
224
|
+
.transpose()?
|
|
225
|
+
.unwrap_or_default();
|
|
210
226
|
|
|
211
227
|
let emulation = wreq_util::Emulation::builder()
|
|
212
|
-
.profile(
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
228
|
+
.profile(
|
|
229
|
+
params
|
|
230
|
+
.profile
|
|
231
|
+
.take()
|
|
232
|
+
.map(|obj| obj.into_ffi())
|
|
233
|
+
.unwrap_or_default(),
|
|
234
|
+
)
|
|
235
|
+
.platform(
|
|
236
|
+
params
|
|
237
|
+
.platform
|
|
238
|
+
.take()
|
|
239
|
+
.map(|os| os.into_ffi())
|
|
240
|
+
.unwrap_or_default(),
|
|
241
|
+
)
|
|
242
|
+
.http2(params.http2.unwrap_or(true))
|
|
243
|
+
.headers(params.headers.unwrap_or(true))
|
|
216
244
|
.build();
|
|
217
245
|
|
|
218
246
|
Ok(Self(emulation))
|
|
@@ -223,11 +251,18 @@ pub fn include(ruby: &Ruby, gem_module: &RModule) -> Result<(), Error> {
|
|
|
223
251
|
// Profile enum binding
|
|
224
252
|
let profile = gem_module.define_class("Profile", ruby.class_object())?;
|
|
225
253
|
profile.define_method("to_s", method!(Profile::to_s, 0))?;
|
|
254
|
+
profile.define_method("==", method!(Profile::equals, 1))?;
|
|
255
|
+
profile.define_method("eql?", method!(Profile::is_eql, 1))?;
|
|
256
|
+
profile.define_method("hash", method!(Profile::hash_value, 0))?;
|
|
226
257
|
Profile::define_constants(profile)?;
|
|
227
258
|
|
|
228
259
|
// Platform enum binding
|
|
229
260
|
let platform = gem_module.define_class("Platform", ruby.class_object())?;
|
|
230
261
|
platform.define_method("to_s", method!(Platform::to_s, 0))?;
|
|
262
|
+
platform.define_method("to_sym", method!(Platform::to_sym, 0))?;
|
|
263
|
+
platform.define_method("==", method!(Platform::equals, 1))?;
|
|
264
|
+
platform.define_method("eql?", method!(Platform::is_eql, 1))?;
|
|
265
|
+
platform.define_method("hash", method!(Platform::hash_value, 0))?;
|
|
231
266
|
Platform::define_constants(platform)?;
|
|
232
267
|
|
|
233
268
|
// Emulation class binding
|
data/src/error.rs
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
use std::{
|
|
2
|
+
cell::{BorrowError, BorrowMutError},
|
|
3
|
+
fmt,
|
|
4
|
+
};
|
|
5
|
+
|
|
1
6
|
use magnus::{
|
|
2
|
-
Error as MagnusError, RModule, Ruby, exception::ExceptionClass, prelude::*,
|
|
7
|
+
Error as MagnusError, RModule, Ruby, error::ErrorType, exception::ExceptionClass, prelude::*,
|
|
8
|
+
value::Lazy,
|
|
3
9
|
};
|
|
4
10
|
use tokio::sync::mpsc::error::SendError;
|
|
5
11
|
|
|
@@ -17,18 +23,24 @@ Potential solutions:
|
|
|
17
23
|
3) Change the order of operations to reference the instance before borrowing it.
|
|
18
24
|
"#;
|
|
19
25
|
|
|
20
|
-
static WREQ: Lazy<RModule> = Lazy::new(|ruby| ruby.define_module(crate::RUBY_MODULE_NAME).unwrap());
|
|
21
|
-
|
|
22
26
|
macro_rules! define_exception {
|
|
23
27
|
($name:ident, $ruby_name:literal, $parent_method:ident) => {
|
|
24
28
|
static $name: Lazy<ExceptionClass> = Lazy::new(|ruby| {
|
|
25
|
-
ruby.
|
|
26
|
-
.
|
|
27
|
-
.
|
|
29
|
+
ruby.class_object()
|
|
30
|
+
.const_get::<_, RModule>(crate::RUBY_MODULE_NAME)
|
|
31
|
+
.and_then(|module| module.const_get::<_, ExceptionClass>($ruby_name))
|
|
32
|
+
.unwrap_or_else(|_| ruby.$parent_method())
|
|
28
33
|
});
|
|
29
34
|
};
|
|
30
35
|
}
|
|
31
36
|
|
|
37
|
+
macro_rules! initialize_exception {
|
|
38
|
+
($ruby:expr, $module:expr, $name:ident, $ruby_name:literal, $parent_method:ident) => {{
|
|
39
|
+
$module.define_error($ruby_name, $ruby.$parent_method())?;
|
|
40
|
+
Lazy::force(&$name, $ruby);
|
|
41
|
+
}};
|
|
42
|
+
}
|
|
43
|
+
|
|
32
44
|
macro_rules! map_wreq_error {
|
|
33
45
|
($ruby:expr, $err:expr, $msg:expr, $($check_method:ident => $exception:ident),* $(,)?) => {
|
|
34
46
|
{
|
|
@@ -73,60 +85,127 @@ define_exception!(DECODING_ERROR, "DecodingError", exception_runtime_error);
|
|
|
73
85
|
define_exception!(BUILDER_ERROR, "BuilderError", exception_runtime_error);
|
|
74
86
|
|
|
75
87
|
/// Memory error constant
|
|
76
|
-
pub fn memory_error() -> MagnusError {
|
|
77
|
-
MagnusError::new(ruby
|
|
88
|
+
pub fn memory_error(ruby: &Ruby) -> MagnusError {
|
|
89
|
+
MagnusError::new(ruby.get_inner(&MEMORY), RACE_CONDITION_ERROR_MSG)
|
|
78
90
|
}
|
|
79
91
|
|
|
80
|
-
/// Create
|
|
81
|
-
pub fn interrupt_error() -> MagnusError {
|
|
82
|
-
MagnusError::new(ruby
|
|
92
|
+
/// Create Ruby's standard thread interruption error.
|
|
93
|
+
pub fn interrupt_error(ruby: &Ruby) -> MagnusError {
|
|
94
|
+
MagnusError::new(ruby.exception_interrupt(), "request interrupted")
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/// Map a Tokio runtime initialization failure to `Wreq::BuilderError`.
|
|
98
|
+
pub fn runtime_initialization_error(ruby: &Ruby, err: &std::io::Error) -> MagnusError {
|
|
99
|
+
MagnusError::new(
|
|
100
|
+
ruby.get_inner(&BUILDER_ERROR),
|
|
101
|
+
format!("failed to initialize Tokio runtime: {err}"),
|
|
102
|
+
)
|
|
83
103
|
}
|
|
84
104
|
|
|
85
105
|
/// LocalJumpError for methods that require a Ruby block.
|
|
86
|
-
pub fn no_block_given_error() -> MagnusError {
|
|
106
|
+
pub fn no_block_given_error(ruby: &Ruby) -> MagnusError {
|
|
107
|
+
MagnusError::new(ruby.exception_local_jump_error(), "no block given (yield)")
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/// Build an `IOError` for writes to a closed request-body sender.
|
|
111
|
+
pub fn closed_body_sender_error(ruby: &Ruby) -> MagnusError {
|
|
112
|
+
MagnusError::new(ruby.exception_io_error(), "closed body sender")
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/// Map a failed body-channel send to `IOError`.
|
|
116
|
+
pub fn body_sender_send_error<T>(ruby: &Ruby, err: SendError<T>) -> MagnusError {
|
|
87
117
|
MagnusError::new(
|
|
88
|
-
ruby
|
|
89
|
-
"
|
|
118
|
+
ruby.exception_io_error(),
|
|
119
|
+
format!("closed body sender: {err}"),
|
|
90
120
|
)
|
|
91
121
|
}
|
|
92
122
|
|
|
93
|
-
/// Map
|
|
94
|
-
pub fn
|
|
123
|
+
/// Map an immutable sender-state borrow failure to `Wreq::BodyError`.
|
|
124
|
+
pub fn body_sender_borrow_error(ruby: &Ruby, err: BorrowError) -> MagnusError {
|
|
95
125
|
MagnusError::new(
|
|
96
|
-
ruby
|
|
97
|
-
format!("
|
|
126
|
+
ruby.get_inner(&BODY_ERROR),
|
|
127
|
+
format!("body sender state is unavailable: {err}"),
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/// Map a mutable sender-state borrow failure to `Wreq::BodyError`.
|
|
132
|
+
pub fn body_sender_borrow_mut_error(ruby: &Ruby, err: BorrowMutError) -> MagnusError {
|
|
133
|
+
MagnusError::new(
|
|
134
|
+
ruby.get_inner(&BODY_ERROR),
|
|
135
|
+
format!("body sender state is unavailable: {err}"),
|
|
98
136
|
)
|
|
99
137
|
}
|
|
100
138
|
|
|
101
139
|
/// Map [`wreq::header::InvalidHeaderName`] to corresponding [`magnus::Error`]
|
|
102
|
-
pub fn
|
|
140
|
+
pub fn header_name_error(ruby: &Ruby, err: wreq::header::InvalidHeaderName) -> MagnusError {
|
|
103
141
|
MagnusError::new(
|
|
104
|
-
ruby
|
|
142
|
+
ruby.get_inner(&BUILDER_ERROR),
|
|
105
143
|
format!("invalid header name: {err}"),
|
|
106
144
|
)
|
|
107
145
|
}
|
|
108
146
|
|
|
109
147
|
/// Map [`wreq::header::InvalidHeaderValue`] to corresponding [`magnus::Error`]
|
|
110
|
-
pub fn
|
|
148
|
+
pub fn header_value_error(ruby: &Ruby, err: wreq::header::InvalidHeaderValue) -> MagnusError {
|
|
111
149
|
MagnusError::new(
|
|
112
|
-
ruby
|
|
150
|
+
ruby.get_inner(&BUILDER_ERROR),
|
|
113
151
|
format!("invalid header value: {err}"),
|
|
114
152
|
)
|
|
115
153
|
}
|
|
116
154
|
|
|
117
|
-
///
|
|
118
|
-
pub fn
|
|
155
|
+
/// Build a `Wreq::BuilderError` for an invalid Ruby header structure.
|
|
156
|
+
pub fn header_type_error(ruby: &Ruby, err: &str) -> MagnusError {
|
|
157
|
+
MagnusError::new(ruby.get_inner(&BUILDER_ERROR), format!("type error: {err}"))
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/// Build a `Wreq::BuilderError` for unsupported request JSON values.
|
|
161
|
+
pub fn json_serialization_error(ruby: &Ruby, err: MagnusError) -> MagnusError {
|
|
119
162
|
MagnusError::new(
|
|
120
|
-
ruby
|
|
121
|
-
format!("
|
|
163
|
+
ruby.get_inner(&BUILDER_ERROR),
|
|
164
|
+
format!("JSON serialization error: {err}"),
|
|
122
165
|
)
|
|
123
166
|
}
|
|
124
167
|
|
|
168
|
+
/// Prefix a Magnus error while preserving its original Ruby exception class.
|
|
169
|
+
pub(crate) fn contextualize_magnus_error(
|
|
170
|
+
err: MagnusError,
|
|
171
|
+
context: fmt::Arguments<'_>,
|
|
172
|
+
) -> MagnusError {
|
|
173
|
+
match err.error_type() {
|
|
174
|
+
ErrorType::Error(class, message) => {
|
|
175
|
+
MagnusError::new(*class, format!("{context}: {message}"))
|
|
176
|
+
}
|
|
177
|
+
ErrorType::Exception(exception) => MagnusError::new(
|
|
178
|
+
exception.exception_class(),
|
|
179
|
+
format!("{context}: {exception}"),
|
|
180
|
+
),
|
|
181
|
+
ErrorType::Jump(_) => err,
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/// Add an option name while preserving the original Ruby exception class.
|
|
186
|
+
pub fn option_value_error(option: &str, err: MagnusError) -> MagnusError {
|
|
187
|
+
contextualize_magnus_error(err, format_args!("invalid value for :{option}"))
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/// Build an `ArgumentError` from a validation message.
|
|
191
|
+
pub fn argument_error(ruby: &Ruby, message: impl Into<String>) -> MagnusError {
|
|
192
|
+
MagnusError::new(ruby.exception_arg_error(), message.into())
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/// Builds a Ruby `RangeError` from a validation message.
|
|
196
|
+
pub fn range_error(ruby: &Ruby, message: impl Into<String>) -> MagnusError {
|
|
197
|
+
MagnusError::new(ruby.exception_range_error(), message.into())
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/// Build a `TypeError` from a conversion message.
|
|
201
|
+
pub fn type_error(ruby: &Ruby, message: impl Into<String>) -> MagnusError {
|
|
202
|
+
MagnusError::new(ruby.exception_type_error(), message.into())
|
|
203
|
+
}
|
|
125
204
|
/// Map [`wreq::Error`] to corresponding [`magnus::Error`]
|
|
126
|
-
pub fn
|
|
205
|
+
pub fn wreq_error(ruby: &Ruby, err: wreq::Error) -> MagnusError {
|
|
127
206
|
let error_msg = err.to_string();
|
|
128
207
|
map_wreq_error!(
|
|
129
|
-
ruby
|
|
208
|
+
ruby,
|
|
130
209
|
err,
|
|
131
210
|
error_msg,
|
|
132
211
|
is_builder => BUILDER_ERROR,
|
|
@@ -143,17 +222,95 @@ pub fn wreq_error_to_magnus(err: wreq::Error) -> MagnusError {
|
|
|
143
222
|
)
|
|
144
223
|
}
|
|
145
224
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
225
|
+
/// Define and retain the Ruby exception classes used by the binding.
|
|
226
|
+
///
|
|
227
|
+
/// # Errors
|
|
228
|
+
///
|
|
229
|
+
/// Returns the Ruby exception raised while defining an error class.
|
|
230
|
+
pub fn include(ruby: &Ruby, gem_module: &RModule) -> Result<(), MagnusError> {
|
|
231
|
+
initialize_exception!(
|
|
232
|
+
ruby,
|
|
233
|
+
gem_module,
|
|
234
|
+
MEMORY,
|
|
235
|
+
"MemoryError",
|
|
236
|
+
exception_runtime_error
|
|
237
|
+
);
|
|
238
|
+
initialize_exception!(
|
|
239
|
+
ruby,
|
|
240
|
+
gem_module,
|
|
241
|
+
CONNECTION_ERROR,
|
|
242
|
+
"ConnectionError",
|
|
243
|
+
exception_runtime_error
|
|
244
|
+
);
|
|
245
|
+
initialize_exception!(
|
|
246
|
+
ruby,
|
|
247
|
+
gem_module,
|
|
248
|
+
PROXY_CONNECTION_ERROR,
|
|
249
|
+
"ProxyConnectionError",
|
|
250
|
+
exception_runtime_error
|
|
251
|
+
);
|
|
252
|
+
initialize_exception!(
|
|
253
|
+
ruby,
|
|
254
|
+
gem_module,
|
|
255
|
+
CONNECTION_RESET_ERROR,
|
|
256
|
+
"ConnectionResetError",
|
|
257
|
+
exception_runtime_error
|
|
258
|
+
);
|
|
259
|
+
initialize_exception!(
|
|
260
|
+
ruby,
|
|
261
|
+
gem_module,
|
|
262
|
+
TLS_ERROR,
|
|
263
|
+
"TlsError",
|
|
264
|
+
exception_runtime_error
|
|
265
|
+
);
|
|
266
|
+
initialize_exception!(
|
|
267
|
+
ruby,
|
|
268
|
+
gem_module,
|
|
269
|
+
REQUEST_ERROR,
|
|
270
|
+
"RequestError",
|
|
271
|
+
exception_runtime_error
|
|
272
|
+
);
|
|
273
|
+
initialize_exception!(
|
|
274
|
+
ruby,
|
|
275
|
+
gem_module,
|
|
276
|
+
STATUS_ERROR,
|
|
277
|
+
"StatusError",
|
|
278
|
+
exception_runtime_error
|
|
279
|
+
);
|
|
280
|
+
initialize_exception!(
|
|
281
|
+
ruby,
|
|
282
|
+
gem_module,
|
|
283
|
+
REDIRECT_ERROR,
|
|
284
|
+
"RedirectError",
|
|
285
|
+
exception_runtime_error
|
|
286
|
+
);
|
|
287
|
+
initialize_exception!(
|
|
288
|
+
ruby,
|
|
289
|
+
gem_module,
|
|
290
|
+
TIMEOUT_ERROR,
|
|
291
|
+
"TimeoutError",
|
|
292
|
+
exception_runtime_error
|
|
293
|
+
);
|
|
294
|
+
initialize_exception!(
|
|
295
|
+
ruby,
|
|
296
|
+
gem_module,
|
|
297
|
+
BODY_ERROR,
|
|
298
|
+
"BodyError",
|
|
299
|
+
exception_runtime_error
|
|
300
|
+
);
|
|
301
|
+
initialize_exception!(
|
|
302
|
+
ruby,
|
|
303
|
+
gem_module,
|
|
304
|
+
DECODING_ERROR,
|
|
305
|
+
"DecodingError",
|
|
306
|
+
exception_runtime_error
|
|
307
|
+
);
|
|
308
|
+
initialize_exception!(
|
|
309
|
+
ruby,
|
|
310
|
+
gem_module,
|
|
311
|
+
BUILDER_ERROR,
|
|
312
|
+
"BuilderError",
|
|
313
|
+
exception_runtime_error
|
|
314
|
+
);
|
|
315
|
+
Ok(())
|
|
159
316
|
}
|
data/src/extractor.rs
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
use magnus::{
|
|
2
|
-
use wreq::
|
|
3
|
-
Proxy,
|
|
4
|
-
header::{HeaderMap, HeaderName, HeaderValue, OrigHeaderMap},
|
|
5
|
-
};
|
|
1
|
+
use magnus::{RHash, RString, Ruby, TryConvert, value::ReprValue};
|
|
2
|
+
use wreq::Proxy;
|
|
6
3
|
|
|
7
|
-
use crate::error::{
|
|
8
|
-
|
|
9
|
-
};
|
|
4
|
+
use crate::error::{option_value_error, wreq_error};
|
|
5
|
+
use crate::options;
|
|
10
6
|
|
|
11
7
|
/// A trait that defines the parameter name for extraction.
|
|
12
8
|
pub trait ExtractorName {
|
|
@@ -32,65 +28,6 @@ where
|
|
|
32
28
|
}
|
|
33
29
|
}
|
|
34
30
|
|
|
35
|
-
// ===== impl Extractor<HeaderMap> =====
|
|
36
|
-
|
|
37
|
-
impl ExtractorName for HeaderMap {
|
|
38
|
-
const NAME: &str = "headers";
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
impl TryConvert for Extractor<HeaderMap> {
|
|
42
|
-
fn try_convert(value: magnus::Value) -> Result<Self, magnus::Error> {
|
|
43
|
-
let ruby = Ruby::get_with(value);
|
|
44
|
-
let keyword = RHash::try_convert(value)?;
|
|
45
|
-
let mut headers = HeaderMap::new();
|
|
46
|
-
|
|
47
|
-
if let Some(hash) = keyword
|
|
48
|
-
.get(ruby.to_symbol(HeaderMap::NAME))
|
|
49
|
-
.and_then(RHash::from_value)
|
|
50
|
-
{
|
|
51
|
-
hash.foreach(|name: RString, value: RString| {
|
|
52
|
-
let name = HeaderName::from_bytes(&name.to_bytes())
|
|
53
|
-
.map_err(header_name_error_to_magnus)?;
|
|
54
|
-
let value = HeaderValue::from_maybe_shared(value.to_bytes())
|
|
55
|
-
.map_err(header_value_error_to_magnus)?;
|
|
56
|
-
headers.insert(name, value);
|
|
57
|
-
|
|
58
|
-
Ok(ForEach::Continue)
|
|
59
|
-
})?;
|
|
60
|
-
|
|
61
|
-
return Ok(Extractor(Some(headers)));
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
Ok(Extractor(None))
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// ===== impl Extractor<OrigHeaderMap> =====
|
|
69
|
-
|
|
70
|
-
impl ExtractorName for OrigHeaderMap {
|
|
71
|
-
const NAME: &str = "orig_headers";
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
impl TryConvert for Extractor<OrigHeaderMap> {
|
|
75
|
-
fn try_convert(value: magnus::Value) -> Result<Self, magnus::Error> {
|
|
76
|
-
let ruby = Ruby::get_with(value);
|
|
77
|
-
let keyword = RHash::try_convert(value)?;
|
|
78
|
-
|
|
79
|
-
if let Some(orig_headers) = keyword
|
|
80
|
-
.get(ruby.to_symbol(OrigHeaderMap::NAME))
|
|
81
|
-
.and_then(RArray::from_value)
|
|
82
|
-
{
|
|
83
|
-
let mut map = OrigHeaderMap::new();
|
|
84
|
-
for value in orig_headers.into_iter().flat_map(RString::from_value) {
|
|
85
|
-
map.insert(value.to_bytes());
|
|
86
|
-
}
|
|
87
|
-
return Ok(Extractor(Some(map)));
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
Ok(Extractor(None))
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
31
|
// ===== impl Extractor<Proxy> =====
|
|
95
32
|
|
|
96
33
|
impl ExtractorName for Proxy {
|
|
@@ -102,16 +39,19 @@ impl TryConvert for Extractor<Proxy> {
|
|
|
102
39
|
let ruby = Ruby::get_with(value);
|
|
103
40
|
let rhash = RHash::try_convert(value)?;
|
|
104
41
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
{
|
|
109
|
-
return
|
|
110
|
-
.map(Some)
|
|
111
|
-
.map(Extractor)
|
|
112
|
-
.map_err(wreq_error_to_magnus);
|
|
42
|
+
let Some(value) = options::get(&ruby, rhash, Proxy::NAME) else {
|
|
43
|
+
return Ok(Extractor(None));
|
|
44
|
+
};
|
|
45
|
+
if value.is_nil() {
|
|
46
|
+
return Ok(Extractor(None));
|
|
113
47
|
}
|
|
114
48
|
|
|
115
|
-
|
|
49
|
+
let proxy =
|
|
50
|
+
RString::try_convert(value).map_err(|error| option_value_error(Proxy::NAME, error))?;
|
|
51
|
+
let proxy = Proxy::all(proxy.to_bytes().as_ref())
|
|
52
|
+
.map_err(|err| wreq_error(&ruby, err))
|
|
53
|
+
.map_err(|error| option_value_error(Proxy::NAME, error))?;
|
|
54
|
+
|
|
55
|
+
Ok(Extractor(Some(proxy)))
|
|
116
56
|
}
|
|
117
57
|
}
|