wreq 1.2.2 → 1.2.3
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 +41 -63
- data/Cargo.toml +1 -1
- data/Gemfile +1 -0
- data/README.md +7 -4
- data/build.rs +7 -0
- data/docs/windows-gnu-tokio-crash.md +70 -0
- data/lib/wreq_ruby/emulate.rb +1 -0
- data/script/build_windows_gnu.ps1 +257 -0
- data/src/arch.rs +33 -0
- data/src/client/body/stream.rs +12 -9
- data/src/client/req.rs +122 -110
- data/src/client/resp.rs +9 -17
- data/src/client.rs +13 -0
- data/src/emulate.rs +1 -0
- data/src/lib.rs +1 -0
- data/src/rt.rs +26 -9
- data/test/client_cookie_test.rb +6 -6
- data/test/client_test.rb +16 -16
- data/test/cookie_test.rb +8 -6
- data/test/error_handling_test.rb +4 -4
- data/test/header_test.rb +1 -1
- data/test/inspect_test.rb +4 -4
- data/test/module_methods_test.rb +11 -11
- data/test/request_parameters_test.rb +30 -30
- data/test/request_test.rb +22 -22
- data/test/response_test.rb +6 -6
- data/test/stream_test.rb +61 -35
- data/test/test_helper.rb +46 -3
- metadata +4 -1
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[switch]$SkipBundleInstall,
|
|
3
|
+
[switch]$SkipToolInstall,
|
|
4
|
+
[switch]$BuildGem,
|
|
5
|
+
[switch]$TestGem,
|
|
6
|
+
[switch]$RunTests,
|
|
7
|
+
[string]$SmokeUrl = $env:WREQ_SMOKE_URL
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
$ErrorActionPreference = "Stop"
|
|
11
|
+
|
|
12
|
+
$target = "x86_64-pc-windows-gnu"
|
|
13
|
+
$platform = "x64-mingw-ucrt"
|
|
14
|
+
$gemPattern = "pkg\wreq-*-$platform.gem"
|
|
15
|
+
if ([string]::IsNullOrWhiteSpace($SmokeUrl)) {
|
|
16
|
+
$SmokeUrl = "https://httpbin.io/get"
|
|
17
|
+
}
|
|
18
|
+
$rubyRoot = Split-Path (Split-Path (Get-Command ruby).Source -Parent) -Parent
|
|
19
|
+
$ucrt = Join-Path $rubyRoot "msys64\ucrt64"
|
|
20
|
+
$ucrtBin = Join-Path $ucrt "bin"
|
|
21
|
+
$msysPackages = @(
|
|
22
|
+
"mingw-w64-ucrt-x86_64-gcc",
|
|
23
|
+
"mingw-w64-ucrt-x86_64-clang",
|
|
24
|
+
"mingw-w64-ucrt-x86_64-cmake",
|
|
25
|
+
"mingw-w64-ucrt-x86_64-pkgconf"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
function Invoke-Step {
|
|
29
|
+
param(
|
|
30
|
+
[string]$Name,
|
|
31
|
+
[scriptblock]$Command
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
Write-Host "==> $Name"
|
|
35
|
+
& $Command
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function Get-MissingUcrtTools {
|
|
39
|
+
$missing = @()
|
|
40
|
+
|
|
41
|
+
if (-not (Test-Path (Join-Path $ucrtBin "gcc.exe")) -or -not (Test-Path (Join-Path $ucrtBin "g++.exe"))) {
|
|
42
|
+
$missing += "gcc/g++"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (-not (Test-Path (Join-Path $ucrtBin "clang.exe")) -or -not (Test-Path (Join-Path $ucrtBin "libclang.dll"))) {
|
|
46
|
+
$missing += "clang/libclang"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (-not (Test-Path (Join-Path $ucrtBin "cmake.exe"))) {
|
|
50
|
+
$missing += "cmake"
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (-not (Test-Path (Join-Path $ucrtBin "pkgconf.exe")) -and -not (Test-Path (Join-Path $ucrtBin "pkg-config.exe"))) {
|
|
54
|
+
$missing += "pkgconf"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
$missing
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function Get-LatestPlatformGem {
|
|
61
|
+
$gem = Get-ChildItem -Path $gemPattern -ErrorAction SilentlyContinue |
|
|
62
|
+
Sort-Object LastWriteTime -Descending |
|
|
63
|
+
Select-Object -First 1
|
|
64
|
+
|
|
65
|
+
if (-not $gem) {
|
|
66
|
+
throw "No Windows GNU platform gem found at '$gemPattern'. Re-run with -BuildGem first."
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
$gem
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function Invoke-RubySmoke {
|
|
73
|
+
param(
|
|
74
|
+
[string]$Name,
|
|
75
|
+
[string]$Code
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
Write-Host "Smoke: $Name"
|
|
79
|
+
ruby -e $Code
|
|
80
|
+
if ($LASTEXITCODE -ne 0) {
|
|
81
|
+
throw "$Name failed with exit code $LASTEXITCODE."
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
Invoke-Step "Check Ruby platform" {
|
|
86
|
+
$rubyArch = & ruby -rrbconfig -e "print RbConfig::CONFIG['arch']"
|
|
87
|
+
if ($rubyArch -ne $platform) {
|
|
88
|
+
throw "Expected Ruby platform '$platform', got '$rubyArch'. Use RubyInstaller UCRT for this build."
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
ruby -v
|
|
92
|
+
ruby -rrbconfig -rrubygems -e "puts RbConfig::CONFIG.values_at('arch', 'host', 'CC').join(%q{ }); puts Gem::Platform.local"
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
Invoke-Step "Install Rust target" {
|
|
96
|
+
$installedTargets = @(rustup target list --installed)
|
|
97
|
+
if ($installedTargets -contains $target) {
|
|
98
|
+
Write-Host "Rust target $target already installed; skipping rustup."
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
rustup target add $target
|
|
103
|
+
if ($LASTEXITCODE -ne 0) {
|
|
104
|
+
throw "Failed to install Rust target $target."
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
Invoke-Step "Check MSYS2 UCRT build tools" {
|
|
109
|
+
$missing = @(Get-MissingUcrtTools)
|
|
110
|
+
if ($missing.Count -eq 0) {
|
|
111
|
+
Write-Host "MSYS2 UCRT build tools already present; skipping pacman."
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if ($SkipToolInstall) {
|
|
116
|
+
throw "Missing MSYS2 UCRT build tools: $($missing -join ', '). Re-run without -SkipToolInstall or install them with ridk."
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
Write-Host "Missing MSYS2 UCRT build tools: $($missing -join ', ')"
|
|
120
|
+
ridk exec pacman -S --needed --noconfirm @msysPackages
|
|
121
|
+
if ($LASTEXITCODE -ne 0) {
|
|
122
|
+
$stillMissing = @(Get-MissingUcrtTools)
|
|
123
|
+
if ($stillMissing.Count -eq 0) {
|
|
124
|
+
Write-Warning "pacman returned exit code $LASTEXITCODE, but all required tools are present; continuing."
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
throw "Failed to install MSYS2 UCRT build tools. Missing: $($stillMissing -join ', '). If pacman cannot lock its database, close other pacman/ridk shells, run PowerShell as Administrator, or install RubyInstaller in a user-writable directory."
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
Invoke-Step "Configure Windows GNU toolchain" {
|
|
133
|
+
$env:CARGO_BUILD_TARGET = $target
|
|
134
|
+
$env:LIBCLANG_PATH = $ucrtBin
|
|
135
|
+
$env:CC_x86_64_pc_windows_gnu = Join-Path $ucrtBin "gcc.exe"
|
|
136
|
+
$env:CXX_x86_64_pc_windows_gnu = Join-Path $ucrtBin "g++.exe"
|
|
137
|
+
$env:CMAKE = Join-Path $ucrtBin "cmake.exe"
|
|
138
|
+
Remove-Item Env:\CMAKE_GENERATOR -ErrorAction SilentlyContinue
|
|
139
|
+
|
|
140
|
+
rustc -Vv
|
|
141
|
+
Write-Host "LIBCLANG_PATH=$env:LIBCLANG_PATH"
|
|
142
|
+
Write-Host "CC_x86_64_pc_windows_gnu=$env:CC_x86_64_pc_windows_gnu"
|
|
143
|
+
Write-Host "CXX_x86_64_pc_windows_gnu=$env:CXX_x86_64_pc_windows_gnu"
|
|
144
|
+
Write-Host "CMAKE=$env:CMAKE"
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (-not $SkipBundleInstall) {
|
|
148
|
+
Invoke-Step "Install Ruby dependencies" {
|
|
149
|
+
bundle install
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
Invoke-Step "Compile native extension" {
|
|
154
|
+
ridk exec ruby -S bundle exec rake compile
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
Invoke-Step "Verify extension loads" {
|
|
158
|
+
ruby -Ilib -rwreq -e "puts Wreq::VERSION; puts Wreq::Client.new.class"
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if ($RunTests) {
|
|
162
|
+
Invoke-Step "Run tests" {
|
|
163
|
+
ridk exec ruby -S bundle exec rake test
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if ($BuildGem) {
|
|
168
|
+
Invoke-Step "Build local platform gem" {
|
|
169
|
+
$rubyMinor = & ruby -e "print RUBY_VERSION[/\A\d+\.\d+/]"
|
|
170
|
+
$dest = "lib\wreq_ruby\$rubyMinor"
|
|
171
|
+
New-Item -ItemType Directory -Force $dest | Out-Null
|
|
172
|
+
Copy-Item "lib\wreq_ruby\wreq_ruby.so" (Join-Path $dest "wreq_ruby.so") -Force
|
|
173
|
+
|
|
174
|
+
ruby script/build_platform_gem.rb $platform
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if ($TestGem) {
|
|
179
|
+
Invoke-Step "Install and smoke test platform gem" {
|
|
180
|
+
$gem = Get-LatestPlatformGem
|
|
181
|
+
$gemHome = Join-Path ([System.IO.Path]::GetTempPath()) "wreq-gem-test-$PID"
|
|
182
|
+
$gemBin = Join-Path $gemHome "bin"
|
|
183
|
+
$testDir = Join-Path ([System.IO.Path]::GetTempPath()) "wreq-gem-test-cwd-$PID"
|
|
184
|
+
|
|
185
|
+
Remove-Item -Recurse -Force $gemHome, $testDir -ErrorAction SilentlyContinue
|
|
186
|
+
New-Item -ItemType Directory -Force $gemHome, $gemBin, $testDir | Out-Null
|
|
187
|
+
|
|
188
|
+
$oldGemHome = $env:GEM_HOME
|
|
189
|
+
$oldGemPath = $env:GEM_PATH
|
|
190
|
+
$oldGemrc = $env:GEMRC
|
|
191
|
+
$oldRubyopt = $env:RUBYOPT
|
|
192
|
+
$oldRubylib = $env:RUBYLIB
|
|
193
|
+
$oldBundleGemfile = $env:BUNDLE_GEMFILE
|
|
194
|
+
$oldBundleBinPath = $env:BUNDLE_BIN_PATH
|
|
195
|
+
$oldBundlerVersion = $env:BUNDLER_VERSION
|
|
196
|
+
$oldSmokeUrl = $env:WREQ_SMOKE_URL
|
|
197
|
+
$oldWreqGemHome = $env:WREQ_GEM_HOME
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
$env:GEM_HOME = $gemHome
|
|
201
|
+
$env:GEM_PATH = $gemHome
|
|
202
|
+
$env:GEMRC = ""
|
|
203
|
+
$env:RUBYOPT = ""
|
|
204
|
+
$env:RUBYLIB = ""
|
|
205
|
+
$env:BUNDLE_GEMFILE = ""
|
|
206
|
+
$env:BUNDLE_BIN_PATH = ""
|
|
207
|
+
$env:BUNDLER_VERSION = ""
|
|
208
|
+
$env:WREQ_SMOKE_URL = $SmokeUrl
|
|
209
|
+
$env:WREQ_GEM_HOME = $gemHome
|
|
210
|
+
|
|
211
|
+
gem install --norc --local --install-dir $gemHome --bindir $gemBin --no-document --force --no-user-install $gem.FullName
|
|
212
|
+
if ($LASTEXITCODE -ne 0) {
|
|
213
|
+
throw "Failed to install $($gem.FullName)."
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
Push-Location $testDir
|
|
217
|
+
try {
|
|
218
|
+
Invoke-RubySmoke "Load installed platform gem" @'
|
|
219
|
+
STDOUT.sync = true
|
|
220
|
+
STDERR.sync = true
|
|
221
|
+
require "wreq"
|
|
222
|
+
spec = Gem.loaded_specs.fetch("wreq")
|
|
223
|
+
expected = File.expand_path(ENV.fetch("WREQ_GEM_HOME"))
|
|
224
|
+
actual = File.expand_path(spec.full_gem_path)
|
|
225
|
+
raise "loaded #{actual}, expected under #{expected}" unless actual.start_with?(expected)
|
|
226
|
+
puts "loaded #{spec.full_name}"
|
|
227
|
+
puts actual
|
|
228
|
+
puts "wreq #{Wreq::VERSION}"
|
|
229
|
+
'@
|
|
230
|
+
|
|
231
|
+
Invoke-RubySmoke "Request through installed platform gem" @'
|
|
232
|
+
STDOUT.sync = true
|
|
233
|
+
STDERR.sync = true
|
|
234
|
+
require "wreq"
|
|
235
|
+
client = Wreq::Client.new
|
|
236
|
+
resp = client.get(ENV.fetch("WREQ_SMOKE_URL"), timeout: 20)
|
|
237
|
+
puts "HTTP #{resp.code}"
|
|
238
|
+
raise "unexpected status #{resp.code}" unless resp.code == 200
|
|
239
|
+
'@
|
|
240
|
+
} finally {
|
|
241
|
+
Pop-Location
|
|
242
|
+
}
|
|
243
|
+
} finally {
|
|
244
|
+
$env:GEM_HOME = $oldGemHome
|
|
245
|
+
$env:GEM_PATH = $oldGemPath
|
|
246
|
+
$env:GEMRC = $oldGemrc
|
|
247
|
+
$env:RUBYOPT = $oldRubyopt
|
|
248
|
+
$env:RUBYLIB = $oldRubylib
|
|
249
|
+
$env:BUNDLE_GEMFILE = $oldBundleGemfile
|
|
250
|
+
$env:BUNDLE_BIN_PATH = $oldBundleBinPath
|
|
251
|
+
$env:BUNDLER_VERSION = $oldBundlerVersion
|
|
252
|
+
$env:WREQ_SMOKE_URL = $oldSmokeUrl
|
|
253
|
+
$env:WREQ_GEM_HOME = $oldWreqGemHome
|
|
254
|
+
Remove-Item -Recurse -Force $gemHome, $testDir -ErrorAction SilentlyContinue
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
data/src/arch.rs
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//! Platform-specific support code.
|
|
2
|
+
//!
|
|
3
|
+
//! Keep this module small and focused on platform quirks that affect linking,
|
|
4
|
+
//! ABI boundaries, or OS APIs used by the Rust extension. Normal HTTP client
|
|
5
|
+
//! behavior should stay in the client/runtime modules so platform workarounds
|
|
6
|
+
//! do not leak into the rest of the binding.
|
|
7
|
+
|
|
8
|
+
#[cfg(all(target_os = "windows", target_env = "gnu"))]
|
|
9
|
+
mod windows_gnu {
|
|
10
|
+
//! Windows GNU support.
|
|
11
|
+
//!
|
|
12
|
+
//! RubyInstaller's GNU/UCRT Ruby exports some symbols with the same names as
|
|
13
|
+
//! Win32 APIs. When GNU ld links this extension against Ruby, those symbols
|
|
14
|
+
//! can shadow the real Windows APIs unless we pin the calls we care about.
|
|
15
|
+
|
|
16
|
+
#[link(name = "kernel32")]
|
|
17
|
+
unsafe extern "system" {
|
|
18
|
+
fn SleepEx(milliseconds: u32, alertable: i32) -> u32;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// RubyInstaller's GNU/UCRT Ruby exports a Ruby-aware Sleep symbol. GNU ld can
|
|
22
|
+
// bind extension calls to that symbol instead of KERNEL32!Sleep, which crashes
|
|
23
|
+
// on native worker threads that have no Ruby TLS. The linker wrapper keeps those
|
|
24
|
+
// calls on the Windows API path.
|
|
25
|
+
#[unsafe(no_mangle)]
|
|
26
|
+
pub extern "system" fn __wrap_Sleep(milliseconds: u32) {
|
|
27
|
+
// SAFETY: SleepEx is a Win32 API. Passing alertable=false matches Sleep's
|
|
28
|
+
// behavior, and any u32 duration is accepted by the API.
|
|
29
|
+
unsafe {
|
|
30
|
+
SleepEx(milliseconds, 0);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
data/src/client/body/stream.rs
CHANGED
|
@@ -5,7 +5,7 @@ use std::{
|
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
use bytes::Bytes;
|
|
8
|
-
use futures_util::{Stream, StreamExt
|
|
8
|
+
use futures_util::{Stream, StreamExt};
|
|
9
9
|
use magnus::{Error, RString, TryConvert, Value};
|
|
10
10
|
use tokio::sync::{
|
|
11
11
|
Mutex,
|
|
@@ -40,13 +40,16 @@ impl BodyReceiver {
|
|
|
40
40
|
|
|
41
41
|
/// Read the next body chunk, converting stream errors into Ruby errors.
|
|
42
42
|
pub fn next(&self) -> Result<Option<Bytes>, Error> {
|
|
43
|
-
rt::try_block_on(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
rt::try_block_on(
|
|
44
|
+
async {
|
|
45
|
+
match self.0.lock().await.as_mut().next().await {
|
|
46
|
+
Some(Ok(data)) => Ok(Some(data)),
|
|
47
|
+
Some(Err(err)) => Err(err),
|
|
48
|
+
None => Ok(None),
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
wreq_error_to_magnus,
|
|
52
|
+
)
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
55
|
|
|
@@ -73,7 +76,7 @@ impl BodySender {
|
|
|
73
76
|
let bytes = data.to_bytes();
|
|
74
77
|
let inner = rb_self.0.read().unwrap();
|
|
75
78
|
if let Some(ref tx) = inner.tx {
|
|
76
|
-
rt::try_block_on(tx.send(bytes)
|
|
79
|
+
rt::try_block_on(tx.send(bytes), mpsc_send_error_to_magnus)?;
|
|
77
80
|
}
|
|
78
81
|
Ok(())
|
|
79
82
|
}
|
data/src/client/req.rs
CHANGED
|
@@ -33,6 +33,7 @@ pub struct Request {
|
|
|
33
33
|
local_address: Option<IpAddr>,
|
|
34
34
|
|
|
35
35
|
/// Bind to an interface by `SO_BINDTODEVICE`.
|
|
36
|
+
#[allow(dead_code)]
|
|
36
37
|
interface: Option<String>,
|
|
37
38
|
|
|
38
39
|
/// The timeout to use for the request.
|
|
@@ -144,119 +145,130 @@ pub fn execute_request<U: AsRef<str>>(
|
|
|
144
145
|
url: U,
|
|
145
146
|
mut request: Request,
|
|
146
147
|
) -> Result<Response, magnus::Error> {
|
|
147
|
-
rt::try_block_on(
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
request.
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
148
|
+
rt::try_block_on(
|
|
149
|
+
async move {
|
|
150
|
+
let mut builder = client.request(method.into_ffi(), url.as_ref());
|
|
151
|
+
|
|
152
|
+
// Emulation options.
|
|
153
|
+
apply_option!(set_if_some_inner, builder, request.emulation, emulation);
|
|
154
|
+
|
|
155
|
+
// Version options.
|
|
156
|
+
apply_option!(
|
|
157
|
+
set_if_some_map,
|
|
158
|
+
builder,
|
|
159
|
+
request.version,
|
|
160
|
+
version,
|
|
161
|
+
Version::into_ffi
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// Timeout options.
|
|
165
|
+
apply_option!(
|
|
166
|
+
set_if_some_map,
|
|
167
|
+
builder,
|
|
168
|
+
request.timeout,
|
|
169
|
+
timeout,
|
|
170
|
+
Duration::from_secs
|
|
171
|
+
);
|
|
172
|
+
apply_option!(
|
|
173
|
+
set_if_some_map,
|
|
174
|
+
builder,
|
|
175
|
+
request.read_timeout,
|
|
176
|
+
read_timeout,
|
|
177
|
+
Duration::from_secs
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
// Network options.
|
|
181
|
+
apply_option!(set_if_some, builder, request.proxy, proxy);
|
|
182
|
+
apply_option!(set_if_some, builder, request.local_address, local_address);
|
|
183
|
+
#[cfg(any(
|
|
184
|
+
target_os = "android",
|
|
185
|
+
target_os = "fuchsia",
|
|
186
|
+
target_os = "illumos",
|
|
187
|
+
target_os = "ios",
|
|
188
|
+
target_os = "linux",
|
|
189
|
+
target_os = "macos",
|
|
190
|
+
target_os = "solaris",
|
|
191
|
+
target_os = "tvos",
|
|
192
|
+
target_os = "visionos",
|
|
193
|
+
target_os = "watchos",
|
|
194
|
+
))]
|
|
195
|
+
apply_option!(set_if_some, builder, request.interface, interface);
|
|
196
|
+
|
|
197
|
+
// Headers options.
|
|
198
|
+
apply_option!(set_if_some_into_inner, builder, request.headers, headers);
|
|
199
|
+
apply_option!(
|
|
200
|
+
set_if_some_inner,
|
|
201
|
+
builder,
|
|
202
|
+
request.orig_headers,
|
|
203
|
+
orig_headers
|
|
204
|
+
);
|
|
205
|
+
apply_option!(
|
|
206
|
+
set_if_some,
|
|
207
|
+
builder,
|
|
208
|
+
request.default_headers,
|
|
209
|
+
default_headers
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
// Cookies options.
|
|
213
|
+
if let Some(cookies) = request.cookies.take() {
|
|
214
|
+
for cookie in cookies.0 {
|
|
215
|
+
builder = builder.header(header::COOKIE, cookie);
|
|
216
|
+
}
|
|
202
217
|
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Authentication options.
|
|
206
|
-
apply_option!(
|
|
207
|
-
set_if_some_map_ref,
|
|
208
|
-
builder,
|
|
209
|
-
request.auth,
|
|
210
|
-
auth,
|
|
211
|
-
AsRef::<str>::as_ref
|
|
212
|
-
);
|
|
213
|
-
apply_option!(set_if_some, builder, request.bearer_auth, bearer_auth);
|
|
214
|
-
if let Some(basic_auth) = request.basic_auth.take() {
|
|
215
|
-
builder = builder.basic_auth(basic_auth.0, basic_auth.1);
|
|
216
|
-
}
|
|
217
218
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
builder
|
|
219
|
+
// Authentication options.
|
|
220
|
+
apply_option!(
|
|
221
|
+
set_if_some_map_ref,
|
|
222
|
+
builder,
|
|
223
|
+
request.auth,
|
|
224
|
+
auth,
|
|
225
|
+
AsRef::<str>::as_ref
|
|
226
|
+
);
|
|
227
|
+
apply_option!(set_if_some, builder, request.bearer_auth, bearer_auth);
|
|
228
|
+
if let Some(basic_auth) = request.basic_auth.take() {
|
|
229
|
+
builder = builder.basic_auth(basic_auth.0, basic_auth.1);
|
|
222
230
|
}
|
|
223
|
-
Some(true) => {
|
|
224
|
-
builder = builder.redirect(
|
|
225
|
-
request
|
|
226
|
-
.max_redirects
|
|
227
|
-
.take()
|
|
228
|
-
.map(wreq::redirect::Policy::limited)
|
|
229
|
-
.unwrap_or_default(),
|
|
230
|
-
);
|
|
231
|
-
}
|
|
232
|
-
None => {}
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
// Compression options.
|
|
236
|
-
apply_option!(set_if_some, builder, request.gzip, gzip);
|
|
237
|
-
apply_option!(set_if_some, builder, request.brotli, brotli);
|
|
238
|
-
apply_option!(set_if_some, builder, request.deflate, deflate);
|
|
239
|
-
apply_option!(set_if_some, builder, request.zstd, zstd);
|
|
240
231
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
232
|
+
// Allow redirects options.
|
|
233
|
+
match request.allow_redirects {
|
|
234
|
+
Some(false) => {
|
|
235
|
+
builder = builder.redirect(wreq::redirect::Policy::none());
|
|
236
|
+
}
|
|
237
|
+
Some(true) => {
|
|
238
|
+
builder = builder.redirect(
|
|
239
|
+
request
|
|
240
|
+
.max_redirects
|
|
241
|
+
.take()
|
|
242
|
+
.map(wreq::redirect::Policy::limited)
|
|
243
|
+
.unwrap_or_default(),
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
None => {}
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Compression options.
|
|
250
|
+
apply_option!(set_if_some, builder, request.gzip, gzip);
|
|
251
|
+
apply_option!(set_if_some, builder, request.brotli, brotli);
|
|
252
|
+
apply_option!(set_if_some, builder, request.deflate, deflate);
|
|
253
|
+
apply_option!(set_if_some, builder, request.zstd, zstd);
|
|
254
|
+
|
|
255
|
+
// Query options.
|
|
256
|
+
apply_option!(set_if_some_ref, builder, request.query, query);
|
|
257
|
+
|
|
258
|
+
// Form options.
|
|
259
|
+
apply_option!(set_if_some_ref, builder, request.form, form);
|
|
260
|
+
|
|
261
|
+
// JSON options.
|
|
262
|
+
apply_option!(set_if_some_ref, builder, request.json, json);
|
|
263
|
+
|
|
264
|
+
// Body options.
|
|
265
|
+
if let Some(body) = request.body.take() {
|
|
266
|
+
builder = builder.body(wreq::Body::from(body));
|
|
267
|
+
}
|
|
254
268
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
.map_err(wreq_error_to_magnus)
|
|
261
|
-
})
|
|
269
|
+
// Send request.
|
|
270
|
+
builder.send().await.map(Response::new)
|
|
271
|
+
},
|
|
272
|
+
wreq_error_to_magnus,
|
|
273
|
+
)
|
|
262
274
|
}
|
data/src/client/resp.rs
CHANGED
|
@@ -81,9 +81,8 @@ impl Response {
|
|
|
81
81
|
Ok(build_response(body))
|
|
82
82
|
} else {
|
|
83
83
|
let bytes = rt::try_block_on(
|
|
84
|
-
BodyExt::collect(body)
|
|
85
|
-
|
|
86
|
-
.map_err(wreq_error_to_magnus),
|
|
84
|
+
BodyExt::collect(body).map_ok(|buf| buf.to_bytes()),
|
|
85
|
+
wreq_error_to_magnus,
|
|
87
86
|
)?;
|
|
88
87
|
|
|
89
88
|
self.body
|
|
@@ -170,7 +169,7 @@ impl Response {
|
|
|
170
169
|
/// Get the response body as bytes.
|
|
171
170
|
pub fn bytes(&self) -> Result<Bytes, Error> {
|
|
172
171
|
let response = self.response(false)?;
|
|
173
|
-
rt::try_block_on(response.bytes()
|
|
172
|
+
rt::try_block_on(response.bytes(), wreq_error_to_magnus)
|
|
174
173
|
}
|
|
175
174
|
|
|
176
175
|
/// Get the full response text given a specific encoding.
|
|
@@ -178,25 +177,18 @@ impl Response {
|
|
|
178
177
|
let args = scan_args::<(), (Option<String>,), (), (), (), ()>(args)?;
|
|
179
178
|
let response = self.response(false)?;
|
|
180
179
|
match args.optional.0 {
|
|
181
|
-
Some(encoding) =>
|
|
182
|
-
response
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
),
|
|
186
|
-
None => rt::try_block_on(response.text().map_err(wreq_error_to_magnus)),
|
|
180
|
+
Some(encoding) => {
|
|
181
|
+
rt::try_block_on(response.text_with_charset(encoding), wreq_error_to_magnus)
|
|
182
|
+
}
|
|
183
|
+
None => rt::try_block_on(response.text(), wreq_error_to_magnus),
|
|
187
184
|
}
|
|
188
185
|
}
|
|
189
186
|
|
|
190
187
|
/// Get the response body as JSON.
|
|
191
188
|
pub fn json(ruby: &Ruby, rb_self: &Self) -> Result<Value, Error> {
|
|
192
189
|
let response = rb_self.response(false)?;
|
|
193
|
-
rt::try_block_on(
|
|
194
|
-
|
|
195
|
-
.json::<Json>()
|
|
196
|
-
.await
|
|
197
|
-
.map_err(wreq_error_to_magnus)?;
|
|
198
|
-
serde_magnus::serialize(ruby, &json)
|
|
199
|
-
})
|
|
190
|
+
let json = rt::try_block_on(response.json::<Json>(), wreq_error_to_magnus)?;
|
|
191
|
+
serde_magnus::serialize(ruby, &json)
|
|
200
192
|
}
|
|
201
193
|
|
|
202
194
|
/// Yield response body chunks to the given Ruby block.
|
data/src/client.rs
CHANGED
|
@@ -104,6 +104,7 @@ struct Builder {
|
|
|
104
104
|
/// Bind to a local IP Address.
|
|
105
105
|
local_address: Option<IpAddr>,
|
|
106
106
|
/// Bind to an interface by `SO_BINDTODEVICE`.
|
|
107
|
+
#[allow(dead_code)]
|
|
107
108
|
interface: Option<String>,
|
|
108
109
|
|
|
109
110
|
// ========= Compression options =========
|
|
@@ -300,6 +301,18 @@ impl Client {
|
|
|
300
301
|
apply_option!(set_if_some, builder, params.proxy, proxy);
|
|
301
302
|
apply_option!(set_if_true, builder, params.no_proxy, no_proxy, false);
|
|
302
303
|
apply_option!(set_if_some, builder, params.local_address, local_address);
|
|
304
|
+
#[cfg(any(
|
|
305
|
+
target_os = "android",
|
|
306
|
+
target_os = "fuchsia",
|
|
307
|
+
target_os = "illumos",
|
|
308
|
+
target_os = "ios",
|
|
309
|
+
target_os = "linux",
|
|
310
|
+
target_os = "macos",
|
|
311
|
+
target_os = "solaris",
|
|
312
|
+
target_os = "tvos",
|
|
313
|
+
target_os = "visionos",
|
|
314
|
+
target_os = "watchos",
|
|
315
|
+
))]
|
|
303
316
|
apply_option!(set_if_some, builder, params.interface, interface);
|
|
304
317
|
|
|
305
318
|
// Compression options.
|
data/src/emulate.rs
CHANGED