wreq 1.2.5 → 1.2.7

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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.cargo/config.toml +4 -0
  3. data/Cargo.lock +135 -119
  4. data/Cargo.toml +11 -3
  5. data/Rakefile +6 -0
  6. data/crates/wreq-util/README.md +1 -1
  7. data/crates/wreq-util/examples/emulate.rs +3 -3
  8. data/crates/wreq-util/src/emulate/macros.rs +13 -11
  9. data/crates/wreq-util/src/emulate/profile/chrome/header.rs +18 -3
  10. data/crates/wreq-util/src/emulate/profile/firefox/header.rs +16 -0
  11. data/crates/wreq-util/src/emulate/profile/opera/header.rs +6 -7
  12. data/crates/wreq-util/tests/client.rs +103 -1
  13. data/docs/windows-gnu-tokio-crash.md +49 -3
  14. data/extconf.rb +4 -0
  15. data/lib/wreq.rb +70 -45
  16. data/lib/wreq_ruby/body.rb +29 -11
  17. data/lib/wreq_ruby/client.rb +88 -55
  18. data/lib/wreq_ruby/cookie.rb +79 -19
  19. data/lib/wreq_ruby/emulate.rb +74 -6
  20. data/lib/wreq_ruby/error.rb +5 -7
  21. data/lib/wreq_ruby/http.rb +74 -0
  22. data/lib/wreq_ruby/response.rb +3 -0
  23. data/script/rust_env.rb +85 -0
  24. data/src/arch.rs +22 -0
  25. data/src/client/body/form.rs +2 -0
  26. data/src/client/body/json.rs +47 -14
  27. data/src/client/body/stream.rs +147 -43
  28. data/src/client/body.rs +11 -15
  29. data/src/client/param.rs +7 -7
  30. data/src/client/req.rs +87 -47
  31. data/src/client/resp.rs +23 -24
  32. data/src/client.rs +310 -230
  33. data/src/cookie.rs +280 -87
  34. data/src/emulate.rs +85 -50
  35. data/src/error.rs +198 -41
  36. data/src/extractor.rs +16 -76
  37. data/src/header.rs +146 -23
  38. data/src/http.rs +62 -33
  39. data/src/lib.rs +26 -20
  40. data/src/macros.rs +71 -46
  41. data/src/options.rs +284 -0
  42. data/src/rt.rs +22 -11
  43. data/src/serde/de/array_deserializer.rs +48 -0
  44. data/src/serde/de/array_enumerator.rs +59 -0
  45. data/src/serde/de/deserializer.rs +307 -0
  46. data/src/serde/de/enum_deserializer.rs +47 -0
  47. data/src/serde/de/hash_deserializer.rs +89 -0
  48. data/src/serde/de/number_deserializer.rs +51 -0
  49. data/src/serde/de/variant_deserializer.rs +101 -0
  50. data/src/serde/de.rs +33 -0
  51. data/src/serde/error.rs +146 -0
  52. data/src/serde/ser/enums.rs +14 -0
  53. data/src/serde/ser/map_serializer.rs +56 -0
  54. data/src/serde/ser/seq_serializer.rs +71 -0
  55. data/src/serde/ser/serializer.rs +194 -0
  56. data/src/serde/ser/struct_serializer.rs +106 -0
  57. data/src/serde/ser/struct_variant_serializer.rs +44 -0
  58. data/src/serde/ser/tuple_variant_serializer.rs +41 -0
  59. data/src/serde/ser.rs +18 -0
  60. data/src/serde/tests.rs +237 -0
  61. data/src/serde.rs +202 -0
  62. data/test/body_sender_test.rb +246 -0
  63. data/test/cookie_test.rb +211 -10
  64. data/test/json_precision_test.rb +209 -0
  65. data/test/option_validation_test.rb +311 -0
  66. data/test/value_semantics_test.rb +238 -0
  67. data/wreq.gemspec +1 -1
  68. metadata +28 -4
  69. data/script/build_windows_gnu.ps1 +0 -264
  70. data/src/header/helper.rs +0 -112
@@ -1,264 +0,0 @@
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 "Sync versioned extension" {
158
- $rubyMinor = & ruby -e "print RUBY_VERSION[/\A\d+\.\d+/]"
159
- $dest = "lib\wreq_ruby\$rubyMinor"
160
- New-Item -ItemType Directory -Force $dest | Out-Null
161
- Copy-Item "lib\wreq_ruby\wreq_ruby.so" (Join-Path $dest "wreq_ruby.so") -Force
162
- }
163
-
164
- Invoke-Step "Verify extension loads" {
165
- ruby -Ilib -rwreq -e "puts Wreq::VERSION; puts Wreq::Client.new.class"
166
- }
167
-
168
- if ($RunTests) {
169
- Invoke-Step "Run tests" {
170
- ridk exec ruby -S bundle exec rake test
171
- }
172
- }
173
-
174
- if ($BuildGem) {
175
- Invoke-Step "Build local platform gem" {
176
- $rubyMinor = & ruby -e "print RUBY_VERSION[/\A\d+\.\d+/]"
177
- $dest = "lib\wreq_ruby\$rubyMinor"
178
- New-Item -ItemType Directory -Force $dest | Out-Null
179
- Copy-Item "lib\wreq_ruby\wreq_ruby.so" (Join-Path $dest "wreq_ruby.so") -Force
180
-
181
- ruby script/build_platform_gem.rb $platform
182
- }
183
- }
184
-
185
- if ($TestGem) {
186
- Invoke-Step "Install and smoke test platform gem" {
187
- $gem = Get-LatestPlatformGem
188
- $gemHome = Join-Path ([System.IO.Path]::GetTempPath()) "wreq-gem-test-$PID"
189
- $gemBin = Join-Path $gemHome "bin"
190
- $testDir = Join-Path ([System.IO.Path]::GetTempPath()) "wreq-gem-test-cwd-$PID"
191
-
192
- Remove-Item -Recurse -Force $gemHome, $testDir -ErrorAction SilentlyContinue
193
- New-Item -ItemType Directory -Force $gemHome, $gemBin, $testDir | Out-Null
194
-
195
- $oldGemHome = $env:GEM_HOME
196
- $oldGemPath = $env:GEM_PATH
197
- $oldGemrc = $env:GEMRC
198
- $oldRubyopt = $env:RUBYOPT
199
- $oldRubylib = $env:RUBYLIB
200
- $oldBundleGemfile = $env:BUNDLE_GEMFILE
201
- $oldBundleBinPath = $env:BUNDLE_BIN_PATH
202
- $oldBundlerVersion = $env:BUNDLER_VERSION
203
- $oldSmokeUrl = $env:WREQ_SMOKE_URL
204
- $oldWreqGemHome = $env:WREQ_GEM_HOME
205
-
206
- try {
207
- $env:GEM_HOME = $gemHome
208
- $env:GEM_PATH = $gemHome
209
- $env:GEMRC = ""
210
- $env:RUBYOPT = ""
211
- $env:RUBYLIB = ""
212
- $env:BUNDLE_GEMFILE = ""
213
- $env:BUNDLE_BIN_PATH = ""
214
- $env:BUNDLER_VERSION = ""
215
- $env:WREQ_SMOKE_URL = $SmokeUrl
216
- $env:WREQ_GEM_HOME = $gemHome
217
-
218
- gem install --norc --local --install-dir $gemHome --bindir $gemBin --no-document --force --no-user-install $gem.FullName
219
- if ($LASTEXITCODE -ne 0) {
220
- throw "Failed to install $($gem.FullName)."
221
- }
222
-
223
- Push-Location $testDir
224
- try {
225
- Invoke-RubySmoke "Load installed platform gem" @'
226
- STDOUT.sync = true
227
- STDERR.sync = true
228
- require "wreq"
229
- spec = Gem.loaded_specs.fetch("wreq")
230
- expected = File.expand_path(ENV.fetch("WREQ_GEM_HOME"))
231
- actual = File.expand_path(spec.full_gem_path)
232
- raise "loaded #{actual}, expected under #{expected}" unless actual.start_with?(expected)
233
- puts "loaded #{spec.full_name}"
234
- puts actual
235
- puts "wreq #{Wreq::VERSION}"
236
- '@
237
-
238
- Invoke-RubySmoke "Request through installed platform gem" @'
239
- STDOUT.sync = true
240
- STDERR.sync = true
241
- require "wreq"
242
- client = Wreq::Client.new
243
- resp = client.get(ENV.fetch("WREQ_SMOKE_URL"), timeout: 20)
244
- puts "HTTP #{resp.code}"
245
- raise "unexpected status #{resp.code}" unless resp.code == 200
246
- '@
247
- } finally {
248
- Pop-Location
249
- }
250
- } finally {
251
- $env:GEM_HOME = $oldGemHome
252
- $env:GEM_PATH = $oldGemPath
253
- $env:GEMRC = $oldGemrc
254
- $env:RUBYOPT = $oldRubyopt
255
- $env:RUBYLIB = $oldRubylib
256
- $env:BUNDLE_GEMFILE = $oldBundleGemfile
257
- $env:BUNDLE_BIN_PATH = $oldBundleBinPath
258
- $env:BUNDLER_VERSION = $oldBundlerVersion
259
- $env:WREQ_SMOKE_URL = $oldSmokeUrl
260
- $env:WREQ_GEM_HOME = $oldWreqGemHome
261
- Remove-Item -Recurse -Force $gemHome, $testDir -ErrorAction SilentlyContinue
262
- }
263
- }
264
- }
data/src/header/helper.rs DELETED
@@ -1,112 +0,0 @@
1
- //! Ruby value conversion helpers for `Wreq::Headers`.
2
-
3
- use bytes::Bytes;
4
- use http::{HeaderName, HeaderValue};
5
- use magnus::{Error, RArray, RString, Symbol, TryConvert, Value, prelude::*, typed_data::Obj};
6
-
7
- use crate::error::{
8
- header_name_error_to_magnus, header_value_error_to_magnus, type_value_error_to_magnus,
9
- };
10
-
11
- use super::Headers;
12
-
13
- /// Maximum number of field-value occurrences supported by `HeaderMap`.
14
- const MAX_HEADER_ENTRIES: usize = 1 << 15;
15
-
16
- /// Build a header collection from a Ruby source object.
17
- ///
18
- /// Accepts another `Wreq::Headers`, a Hash, or any object whose `to_a` result
19
- /// contains two-element name-value pairs. Array values are delegated to
20
- /// [`Headers::append`] so each value remains a separate occurrence.
21
- pub(super) fn from_source(source: Value) -> Result<Headers, Error> {
22
- if let Ok(headers) = Obj::<Headers>::try_convert(source) {
23
- return Ok((*headers).clone());
24
- }
25
- if !source.respond_to("to_a", false)? {
26
- return Err(type_value_error_to_magnus(
27
- "Expected Headers, a Hash, or an enumerable of pairs",
28
- ));
29
- }
30
-
31
- let pairs: RArray = source.funcall_public("to_a", ())?;
32
- let headers = Headers::default();
33
- for pair in pairs {
34
- let pair = RArray::try_convert(pair)
35
- .map_err(|_| type_value_error_to_magnus("Expected each header entry to be a pair"))?;
36
- if pair.len() != 2 {
37
- return Err(type_value_error_to_magnus(
38
- "Expected each header entry to contain a name and value",
39
- ));
40
- }
41
-
42
- headers.append(pair.entry(0)?, pair.entry(1)?)?;
43
- }
44
- Ok(headers)
45
- }
46
-
47
- /// Convert a Ruby String or Symbol into a normalized HTTP header name.
48
- ///
49
- /// Symbol underscores are changed to hyphens before [`HeaderName`] validates
50
- /// and normalizes the name. Other Ruby types produce `Wreq::BuilderError`.
51
- pub(super) fn parse_header_name(value: Value) -> Result<HeaderName, Error> {
52
- let name = match (RString::from_value(value), Symbol::from_value(value)) {
53
- (Some(name), _) => name.to_bytes(),
54
- (None, Some(name)) => Bytes::from(name.name()?.replace('_', "-")),
55
- (None, None) => {
56
- return Err(type_value_error_to_magnus(
57
- "Expected a String or Symbol header name",
58
- ));
59
- }
60
- };
61
- HeaderName::from_bytes(name.as_ref()).map_err(header_name_error_to_magnus)
62
- }
63
-
64
- /// Convert a Ruby String or Array of Strings into validated header values.
65
- ///
66
- /// Each Array element becomes one [`HeaderValue`]. An empty Array therefore
67
- /// produces no values, allowing `set` to remove a header and `append` to do
68
- /// nothing.
69
- pub(super) fn parse_header_values(value: Value) -> Result<Vec<HeaderValue>, Error> {
70
- if let Some(values) = RArray::from_value(value) {
71
- values.into_iter().map(parse_header_value).collect()
72
- } else {
73
- Ok(vec![parse_header_value(value)?])
74
- }
75
- }
76
-
77
- /// Convert one Ruby String into a validated HTTP header value.
78
- ///
79
- /// Invalid Ruby types and bytes rejected by [`HeaderValue`] are mapped to
80
- /// `Wreq::BuilderError`.
81
- fn parse_header_value(value: Value) -> Result<HeaderValue, Error> {
82
- let value = RString::try_convert(value)
83
- .map_err(|_| type_value_error_to_magnus("Expected a String header value"))?;
84
- HeaderValue::from_maybe_shared(value.to_bytes()).map_err(header_value_error_to_magnus)
85
- }
86
-
87
- /// Validate the resulting number of header occurrences before a mutation.
88
- ///
89
- /// `current` is the collection length, `replaced` is the number of existing
90
- /// occurrences removed by `set`, and `added` is the incoming value count.
91
- /// Checked arithmetic prevents overflow; an invalid calculation or a result
92
- /// above the native [`HeaderMap`](http::HeaderMap) limit returns
93
- /// `Wreq::BuilderError` without mutating the collection.
94
- pub(super) fn ensure_header_count(
95
- current: usize,
96
- replaced: usize,
97
- added: usize,
98
- ) -> Result<(), Error> {
99
- let count = current
100
- .checked_sub(replaced)
101
- .and_then(|count| count.checked_add(added));
102
- if count.is_some_and(|count| count <= MAX_HEADER_ENTRIES) {
103
- Ok(())
104
- } else {
105
- Err(header_count_error())
106
- }
107
- }
108
-
109
- /// Build the error returned when the native header map reaches its entry limit.
110
- pub(super) fn header_count_error() -> Error {
111
- type_value_error_to_magnus("Header collection exceeds 32,768 entries")
112
- }