wreq 1.0.0
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 +7 -0
- data/Cargo.toml +54 -0
- data/Gemfile +17 -0
- data/LICENSE +201 -0
- data/README.md +150 -0
- data/Rakefile +90 -0
- data/build.rs +9 -0
- data/examples/body.rb +42 -0
- data/examples/client.rb +33 -0
- data/examples/emulation_request.rb +37 -0
- data/examples/headers.rb +27 -0
- data/examples/proxy.rb +113 -0
- data/examples/send_stream.rb +85 -0
- data/examples/stream.rb +14 -0
- data/examples/thread_interrupt.rb +83 -0
- data/extconf.rb +7 -0
- data/lib/wreq.rb +313 -0
- data/lib/wreq_ruby/body.rb +36 -0
- data/lib/wreq_ruby/client.rb +516 -0
- data/lib/wreq_ruby/cookie.rb +144 -0
- data/lib/wreq_ruby/emulation.rb +186 -0
- data/lib/wreq_ruby/error.rb +159 -0
- data/lib/wreq_ruby/header.rb +197 -0
- data/lib/wreq_ruby/http.rb +132 -0
- data/lib/wreq_ruby/response.rb +208 -0
- data/script/build_platform_gem.rb +34 -0
- data/src/client/body/form.rs +2 -0
- data/src/client/body/json.rs +16 -0
- data/src/client/body/stream.rs +148 -0
- data/src/client/body.rs +57 -0
- data/src/client/param.rs +19 -0
- data/src/client/query.rs +2 -0
- data/src/client/req.rs +251 -0
- data/src/client/resp.rs +250 -0
- data/src/client.rs +392 -0
- data/src/cookie.rs +277 -0
- data/src/emulation.rs +317 -0
- data/src/error.rs +147 -0
- data/src/extractor.rs +199 -0
- data/src/gvl.rs +154 -0
- data/src/header.rs +177 -0
- data/src/http.rs +127 -0
- data/src/lib.rs +97 -0
- data/src/macros.rs +118 -0
- data/src/rt.rs +47 -0
- data/test/client_cookie_test.rb +46 -0
- data/test/client_test.rb +136 -0
- data/test/cookie_test.rb +166 -0
- data/test/emulation_test.rb +21 -0
- data/test/error_handling_test.rb +89 -0
- data/test/header_test.rb +290 -0
- data/test/module_methods_test.rb +75 -0
- data/test/request_parameters_test.rb +175 -0
- data/test/request_test.rb +234 -0
- data/test/response_test.rb +69 -0
- data/test/stream_test.rb +81 -0
- data/test/test_helper.rb +9 -0
- data/wreq.gemspec +68 -0
- metadata +112 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wreq
|
|
4
|
+
# Device emulation enumeration backed by Rust.
|
|
5
|
+
#
|
|
6
|
+
# Variants are exposed as constants under this class.
|
|
7
|
+
# Each constant is an instance of {Wreq::EmulationDevice}.
|
|
8
|
+
#
|
|
9
|
+
# @example Using predefined constants
|
|
10
|
+
# device = Wreq::EmulationDevice::Chrome117
|
|
11
|
+
# device.class #=> Wreq::EmulationDevice
|
|
12
|
+
class EmulationDevice
|
|
13
|
+
# Constants are set by the native extension at initialization.
|
|
14
|
+
# These stubs are for documentation only.
|
|
15
|
+
unless const_defined?(:Chrome100)
|
|
16
|
+
Chrome100 = nil
|
|
17
|
+
Chrome101 = nil
|
|
18
|
+
Chrome104 = nil
|
|
19
|
+
Chrome105 = nil
|
|
20
|
+
Chrome106 = nil
|
|
21
|
+
Chrome107 = nil
|
|
22
|
+
Chrome108 = nil
|
|
23
|
+
Chrome109 = nil
|
|
24
|
+
Chrome110 = nil
|
|
25
|
+
Chrome114 = nil
|
|
26
|
+
Chrome116 = nil
|
|
27
|
+
Chrome117 = nil
|
|
28
|
+
Chrome118 = nil
|
|
29
|
+
Chrome119 = nil
|
|
30
|
+
Chrome120 = nil
|
|
31
|
+
Chrome123 = nil
|
|
32
|
+
Chrome124 = nil
|
|
33
|
+
Chrome126 = nil
|
|
34
|
+
Chrome127 = nil
|
|
35
|
+
Chrome128 = nil
|
|
36
|
+
Chrome129 = nil
|
|
37
|
+
Chrome130 = nil
|
|
38
|
+
Chrome131 = nil
|
|
39
|
+
Chrome132 = nil
|
|
40
|
+
Chrome133 = nil
|
|
41
|
+
Chrome134 = nil
|
|
42
|
+
Chrome135 = nil
|
|
43
|
+
Chrome136 = nil
|
|
44
|
+
Chrome137 = nil
|
|
45
|
+
Chrome138 = nil
|
|
46
|
+
Chrome139 = nil
|
|
47
|
+
Chrome140 = nil
|
|
48
|
+
Chrome141 = nil
|
|
49
|
+
Chrome142 = nil
|
|
50
|
+
Chrome143 = nil
|
|
51
|
+
Chrome144 = nil
|
|
52
|
+
Chrome145 = nil
|
|
53
|
+
Edge101 = nil
|
|
54
|
+
Edge122 = nil
|
|
55
|
+
Edge127 = nil
|
|
56
|
+
Edge131 = nil
|
|
57
|
+
Edge134 = nil
|
|
58
|
+
Edge135 = nil
|
|
59
|
+
Edge136 = nil
|
|
60
|
+
Edge137 = nil
|
|
61
|
+
Edge138 = nil
|
|
62
|
+
Edge139 = nil
|
|
63
|
+
Edge140 = nil
|
|
64
|
+
Edge141 = nil
|
|
65
|
+
Edge142 = nil
|
|
66
|
+
Edge143 = nil
|
|
67
|
+
Edge144 = nil
|
|
68
|
+
Edge145 = nil
|
|
69
|
+
Firefox109 = nil
|
|
70
|
+
Firefox117 = nil
|
|
71
|
+
Firefox128 = nil
|
|
72
|
+
Firefox133 = nil
|
|
73
|
+
Firefox135 = nil
|
|
74
|
+
FirefoxPrivate135 = nil
|
|
75
|
+
FirefoxAndroid135 = nil
|
|
76
|
+
Firefox136 = nil
|
|
77
|
+
FirefoxPrivate136 = nil
|
|
78
|
+
Firefox139 = nil
|
|
79
|
+
Firefox142 = nil
|
|
80
|
+
Firefox143 = nil
|
|
81
|
+
Firefox144 = nil
|
|
82
|
+
Firefox145 = nil
|
|
83
|
+
Firefox146 = nil
|
|
84
|
+
Firefox147 = nil
|
|
85
|
+
SafariIos17_2 = nil
|
|
86
|
+
SafariIos17_4_1 = nil
|
|
87
|
+
SafariIos16_5 = nil
|
|
88
|
+
Safari15_3 = nil
|
|
89
|
+
Safari15_5 = nil
|
|
90
|
+
Safari15_6_1 = nil
|
|
91
|
+
Safari16 = nil
|
|
92
|
+
Safari16_5 = nil
|
|
93
|
+
Safari17_0 = nil
|
|
94
|
+
Safari17_2_1 = nil
|
|
95
|
+
Safari17_4_1 = nil
|
|
96
|
+
Safari17_5 = nil
|
|
97
|
+
Safari17_6 = nil
|
|
98
|
+
Safari18 = nil
|
|
99
|
+
SafariIPad18 = nil
|
|
100
|
+
Safari18_2 = nil
|
|
101
|
+
Safari18_3 = nil
|
|
102
|
+
Safari18_3_1 = nil
|
|
103
|
+
SafariIos18_1_1 = nil
|
|
104
|
+
Safari18_5 = nil
|
|
105
|
+
Safari26 = nil
|
|
106
|
+
Safari26_1 = nil
|
|
107
|
+
Safari26_2 = nil
|
|
108
|
+
SafariIos26 = nil
|
|
109
|
+
SafariIos26_2 = nil
|
|
110
|
+
SafariIPad26 = nil
|
|
111
|
+
SafariIpad26_2 = nil
|
|
112
|
+
OkHttp3_9 = nil
|
|
113
|
+
OkHttp3_11 = nil
|
|
114
|
+
OkHttp3_13 = nil
|
|
115
|
+
OkHttp3_14 = nil
|
|
116
|
+
OkHttp4_9 = nil
|
|
117
|
+
OkHttp4_10 = nil
|
|
118
|
+
OkHttp4_12 = nil
|
|
119
|
+
OkHttp5 = nil
|
|
120
|
+
Opera116 = nil
|
|
121
|
+
Opera117 = nil
|
|
122
|
+
Opera118 = nil
|
|
123
|
+
Opera119 = nil
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
unless method_defined?(:to_s)
|
|
127
|
+
# Returns a string representation of the emulation device.
|
|
128
|
+
# @return [String] Emulation device as string
|
|
129
|
+
def to_s
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Operating system emulation enumeration backed by Rust.
|
|
135
|
+
#
|
|
136
|
+
# Variants are exposed as constants under this class.
|
|
137
|
+
# Each constant is an instance of {Wreq::EmulationOS}.
|
|
138
|
+
#
|
|
139
|
+
# @example Using predefined constants
|
|
140
|
+
# os = Wreq::EmulationOS::Windows
|
|
141
|
+
# os.class #=> Wreq::EmulationOS
|
|
142
|
+
class EmulationOS
|
|
143
|
+
# Constants are set by the native extension at initialization.
|
|
144
|
+
# These stubs are for documentation only.
|
|
145
|
+
unless const_defined?(:Windows)
|
|
146
|
+
Windows = nil
|
|
147
|
+
MacOS = nil
|
|
148
|
+
Linux = nil
|
|
149
|
+
Android = nil
|
|
150
|
+
IOS = nil
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
unless method_defined?(:to_s)
|
|
154
|
+
# Returns a string representation of the emulation OS.
|
|
155
|
+
# @return [String] Emulation OS as string
|
|
156
|
+
def to_s
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Emulation option wrapper.
|
|
162
|
+
#
|
|
163
|
+
# This class wraps device and OS emulation options and provides
|
|
164
|
+
# a unified interface for browser environment simulation.
|
|
165
|
+
# The actual implementation is provided by Rust for performance.
|
|
166
|
+
#
|
|
167
|
+
# @example Create an emulation option
|
|
168
|
+
# emu = Wreq::Emulation.new(device: Wreq::EmulationDevice::Chrome117, os: Wreq::EmulationOS::Windows)
|
|
169
|
+
#
|
|
170
|
+
# @param device [Wreq::EmulationDevice] Device profile (optional)
|
|
171
|
+
# @param os [Wreq::EmulationOS] Operating system profile (optional)
|
|
172
|
+
# @param skip_http2 [Boolean] Whether to skip HTTP/2 (optional)
|
|
173
|
+
# @param skip_headers [Boolean] Whether to skip default headers (optional)
|
|
174
|
+
class Emulation
|
|
175
|
+
# Native fields and methods are set by the extension.
|
|
176
|
+
# This stub is for documentation only.
|
|
177
|
+
unless method_defined?(:new)
|
|
178
|
+
# @param device [Wreq::EmulationDevice] Device profile (optional)
|
|
179
|
+
# @param os [Wreq::EmulationOS] Operating system profile (optional)
|
|
180
|
+
# @param skip_http2 [Boolean] Whether to skip HTTP/2 (optional)
|
|
181
|
+
# @param skip_headers [Boolean] Whether to skip default headers (optional)
|
|
182
|
+
def self.new(device: nil, os: nil, skip_http2: false, skip_headers: false)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
unless defined?(Wreq)
|
|
4
|
+
module Wreq
|
|
5
|
+
# System-level and runtime errors
|
|
6
|
+
|
|
7
|
+
# Memory allocation failed.
|
|
8
|
+
class MemoryError < StandardError; end
|
|
9
|
+
|
|
10
|
+
# Network connection errors
|
|
11
|
+
|
|
12
|
+
# Connection to the server failed.
|
|
13
|
+
#
|
|
14
|
+
# Raised when the client cannot establish a connection to the server.
|
|
15
|
+
#
|
|
16
|
+
# @example
|
|
17
|
+
# begin
|
|
18
|
+
# client.get("http://localhost:9999")
|
|
19
|
+
# rescue Wreq::ConnectionError => e
|
|
20
|
+
# puts "Connection failed: #{e.message}"
|
|
21
|
+
# retry_with_backoff
|
|
22
|
+
# end
|
|
23
|
+
class ConnectionError < StandardError; end
|
|
24
|
+
|
|
25
|
+
# Proxy Connection to the server failed.
|
|
26
|
+
#
|
|
27
|
+
# Raised when the client cannot establish a connection to the proxy server.
|
|
28
|
+
# @example
|
|
29
|
+
# begin
|
|
30
|
+
# client.get("http://example.com", proxy: "http://invalid-proxy:8080")
|
|
31
|
+
# rescue Wreq::ProxyConnectionError => e
|
|
32
|
+
# puts "Proxy connection failed: #{e.message}"
|
|
33
|
+
# retry_with_different_proxy
|
|
34
|
+
# end
|
|
35
|
+
class ProxyConnectionError < StandardError; end
|
|
36
|
+
|
|
37
|
+
# Connection was reset by the server.
|
|
38
|
+
#
|
|
39
|
+
# Raised when the server closes the connection unexpectedly.
|
|
40
|
+
#
|
|
41
|
+
# @example
|
|
42
|
+
# rescue Wreq::ConnectionResetError => e
|
|
43
|
+
# puts "Connection reset: #{e.message}"
|
|
44
|
+
# end
|
|
45
|
+
class ConnectionResetError < StandardError; end
|
|
46
|
+
|
|
47
|
+
# TLS/SSL error occurred.
|
|
48
|
+
#
|
|
49
|
+
# Raised when there's an error with TLS/SSL, such as certificate
|
|
50
|
+
# verification failure or protocol mismatch.
|
|
51
|
+
#
|
|
52
|
+
# @example
|
|
53
|
+
# begin
|
|
54
|
+
# client.get("https://self-signed.badssl.com")
|
|
55
|
+
# rescue Wreq::TlsError => e
|
|
56
|
+
# puts "TLS error: #{e.message}"
|
|
57
|
+
# end
|
|
58
|
+
unless const_defined?(:TlsError)
|
|
59
|
+
class TlsError < StandardError; end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# HTTP protocol and request/response errors
|
|
63
|
+
|
|
64
|
+
# Request failed.
|
|
65
|
+
#
|
|
66
|
+
# Generic error for request failures that don't fit other categories.
|
|
67
|
+
#
|
|
68
|
+
# @example
|
|
69
|
+
# rescue Wreq::RequestError => e
|
|
70
|
+
# puts "Request failed: #{e.message}"
|
|
71
|
+
# end
|
|
72
|
+
class RequestError < StandardError; end
|
|
73
|
+
|
|
74
|
+
# HTTP status code indicates an error.
|
|
75
|
+
#
|
|
76
|
+
# Raised when the server returns an error status code (4xx or 5xx).
|
|
77
|
+
#
|
|
78
|
+
# @example
|
|
79
|
+
# begin
|
|
80
|
+
# response = client.get("https://httpbin.io/status/404")
|
|
81
|
+
# rescue Wreq::StatusError => e
|
|
82
|
+
# puts "HTTP error: #{e.message}"
|
|
83
|
+
# # e.response contains the full response
|
|
84
|
+
# end
|
|
85
|
+
class StatusError < StandardError; end
|
|
86
|
+
|
|
87
|
+
# Redirect handling failed.
|
|
88
|
+
#
|
|
89
|
+
# Raised when too many redirects occur or redirect logic fails.
|
|
90
|
+
#
|
|
91
|
+
# @example
|
|
92
|
+
# begin
|
|
93
|
+
# client = Wreq::Client.new(max_redirects: 3)
|
|
94
|
+
# client.get("https://httpbin.io/redirect/10")
|
|
95
|
+
# rescue Wreq::RedirectError => e
|
|
96
|
+
# puts "Too many redirects: #{e.message}"
|
|
97
|
+
# end
|
|
98
|
+
class RedirectError < StandardError; end
|
|
99
|
+
|
|
100
|
+
# Request timed out.
|
|
101
|
+
#
|
|
102
|
+
# Raised when the request exceeds the configured timeout.
|
|
103
|
+
#
|
|
104
|
+
# @example
|
|
105
|
+
# begin
|
|
106
|
+
# client = Wreq::Client.new(timeout: 5)
|
|
107
|
+
# client.get("https://httpbin.io/delay/10")
|
|
108
|
+
# rescue Wreq::TimeoutError => e
|
|
109
|
+
# puts "Request timed out: #{e.message}"
|
|
110
|
+
# retry_with_longer_timeout
|
|
111
|
+
# end
|
|
112
|
+
class TimeoutError < StandardError; end
|
|
113
|
+
|
|
114
|
+
# Data processing and encoding errors
|
|
115
|
+
|
|
116
|
+
# Response body processing failed.
|
|
117
|
+
#
|
|
118
|
+
# Raised when there's an error reading or processing the response body.
|
|
119
|
+
#
|
|
120
|
+
# @example
|
|
121
|
+
# rescue Wreq::BodyError => e
|
|
122
|
+
# puts "Body error: #{e.message}"
|
|
123
|
+
# end
|
|
124
|
+
class BodyError < StandardError; end
|
|
125
|
+
|
|
126
|
+
# Decoding response failed.
|
|
127
|
+
#
|
|
128
|
+
# Raised when response content cannot be decoded (e.g., invalid UTF-8,
|
|
129
|
+
# malformed JSON, corrupted compression).
|
|
130
|
+
#
|
|
131
|
+
# @example
|
|
132
|
+
# begin
|
|
133
|
+
# response = client.get("https://example.com/invalid-utf8")
|
|
134
|
+
# response.text # May raise DecodingError
|
|
135
|
+
# rescue Wreq::DecodingError => e
|
|
136
|
+
# puts "Decoding error: #{e.message}"
|
|
137
|
+
# # Fall back to binary data
|
|
138
|
+
# data = response.body
|
|
139
|
+
# end
|
|
140
|
+
class DecodingError < StandardError; end
|
|
141
|
+
|
|
142
|
+
# Configuration and builder errors
|
|
143
|
+
|
|
144
|
+
# Client configuration is invalid.
|
|
145
|
+
#
|
|
146
|
+
# Raised when the client is configured with invalid options.
|
|
147
|
+
#
|
|
148
|
+
# @example
|
|
149
|
+
# begin
|
|
150
|
+
# client = Wreq::Client.new(
|
|
151
|
+
# proxy: "invalid://proxy",
|
|
152
|
+
# timeout: -1
|
|
153
|
+
# )
|
|
154
|
+
# rescue Wreq::BuilderError => e
|
|
155
|
+
# puts "Invalid configuration: #{e.message}"
|
|
156
|
+
# end
|
|
157
|
+
class BuilderError < StandardError; end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
unless defined?(Wreq)
|
|
4
|
+
module Wreq
|
|
5
|
+
# HTTP headers collection.
|
|
6
|
+
#
|
|
7
|
+
# Provides efficient access to HTTP headers with case-insensitive lookups.
|
|
8
|
+
# Headers are created by the native extension and cannot be directly instantiated.
|
|
9
|
+
#
|
|
10
|
+
# All header names are case-insensitive. Multiple values for the same header
|
|
11
|
+
# are supported through the `get_all` method.
|
|
12
|
+
#
|
|
13
|
+
# @example Accessing response headers
|
|
14
|
+
# response = Wreq.get("https://example.com")
|
|
15
|
+
# headers = response.headers
|
|
16
|
+
# content_type = headers["Content-Type"]
|
|
17
|
+
# content_type = headers.get("content-type") # Same, case-insensitive
|
|
18
|
+
#
|
|
19
|
+
# @example Getting all values for a header
|
|
20
|
+
# accept_values = headers.get_all("Accept")
|
|
21
|
+
# # => ["application/json", "text/html"]
|
|
22
|
+
#
|
|
23
|
+
# @example Modifying headers
|
|
24
|
+
# headers.set("X-Custom-Header", "value")
|
|
25
|
+
# headers["Authorization"] = "Bearer token"
|
|
26
|
+
# headers.append("Accept", "application/xml")
|
|
27
|
+
#
|
|
28
|
+
# @example Iterating headers
|
|
29
|
+
# headers.each do |name, value|
|
|
30
|
+
# puts "#{name}: #{value}"
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# @example Converting to hash
|
|
34
|
+
# hash = headers.to_h
|
|
35
|
+
# hash["content-type"] # => "text/html"
|
|
36
|
+
class Headers
|
|
37
|
+
# Create a new empty Headers collection.
|
|
38
|
+
#
|
|
39
|
+
# @return [Wreq::Headers] New headers instance
|
|
40
|
+
# @example
|
|
41
|
+
# headers = Wreq::Headers.new
|
|
42
|
+
# headers.set("Content-Type", "application/json")
|
|
43
|
+
def self.new
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Get a header value by name (case-insensitive).
|
|
47
|
+
#
|
|
48
|
+
# Returns the first value if multiple values exist for the same header.
|
|
49
|
+
#
|
|
50
|
+
# @param name [String] Header name (case-insensitive)
|
|
51
|
+
# @return [String, nil] Header value, or nil if not found
|
|
52
|
+
# @example
|
|
53
|
+
# headers.get("Content-Type") # => "application/json"
|
|
54
|
+
# headers.get("content-type") # => "application/json" (same)
|
|
55
|
+
# headers.get("X-Nonexistent") # => nil
|
|
56
|
+
def get(name)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Get all values for a header name (case-insensitive).
|
|
60
|
+
#
|
|
61
|
+
# Useful when a header can have multiple values (e.g., Accept, Set-Cookie).
|
|
62
|
+
#
|
|
63
|
+
# @param name [String] Header name (case-insensitive)
|
|
64
|
+
# @return [Array<String>] All values for this header (empty array if not found)
|
|
65
|
+
# @example
|
|
66
|
+
# headers.get_all("Accept")
|
|
67
|
+
# # => ["application/json", "text/html", "application/xml"]
|
|
68
|
+
# headers.get_all("X-Nonexistent") # => []
|
|
69
|
+
def get_all(name)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Set a header value, replacing any existing values.
|
|
73
|
+
#
|
|
74
|
+
# @param name [String] Header name
|
|
75
|
+
# @param value [String] Header value
|
|
76
|
+
# @return [void]
|
|
77
|
+
# @raise [Wreq::BuilderError] if name or value contains invalid characters
|
|
78
|
+
# @example
|
|
79
|
+
# headers.set("Content-Type", "application/json")
|
|
80
|
+
# headers.set("X-Custom-Header", "my-value")
|
|
81
|
+
def set(name, value)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Append a header value without replacing existing values.
|
|
85
|
+
#
|
|
86
|
+
# Adds a new value for the header, preserving any existing values.
|
|
87
|
+
# Useful for headers that can have multiple values.
|
|
88
|
+
#
|
|
89
|
+
# @param name [String] Header name
|
|
90
|
+
# @param value [String] Header value to append
|
|
91
|
+
# @return [void]
|
|
92
|
+
# @raise [Wreq::BuilderError] if name or value contains invalid characters
|
|
93
|
+
# @example
|
|
94
|
+
# headers.set("Accept", "application/json")
|
|
95
|
+
# headers.append("Accept", "text/html")
|
|
96
|
+
# headers.get_all("Accept") # => ["application/json", "text/html"]
|
|
97
|
+
def append(name, value)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Remove all values for a header name.
|
|
101
|
+
#
|
|
102
|
+
# @param name [String] Header name (case-insensitive)
|
|
103
|
+
# @return [String, nil] The removed value (first one if multiple), or nil
|
|
104
|
+
# @example
|
|
105
|
+
# headers.remove("Authorization") # => "Bearer token"
|
|
106
|
+
# headers.remove("X-Nonexistent") # => nil
|
|
107
|
+
def remove(name)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Check if a header exists (case-insensitive).
|
|
111
|
+
#
|
|
112
|
+
# @param name [String] Header name
|
|
113
|
+
# @return [Boolean] true if the header exists
|
|
114
|
+
# @example
|
|
115
|
+
# headers.contains?("Content-Type") # => true
|
|
116
|
+
# headers.contains?("X-Missing") # => false
|
|
117
|
+
def contains?(name)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Check if a header key exists (alias for {#contains?}).
|
|
121
|
+
#
|
|
122
|
+
# @param name [String] Header name
|
|
123
|
+
# @return [Boolean] true if the header exists
|
|
124
|
+
# @example
|
|
125
|
+
# headers.key?("Accept") # => true
|
|
126
|
+
def key?(name)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Get the number of headers.
|
|
130
|
+
#
|
|
131
|
+
# @return [Integer] Total number of unique header names
|
|
132
|
+
# @example
|
|
133
|
+
# headers.length # => 12
|
|
134
|
+
def length
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Check if there are no headers.
|
|
138
|
+
#
|
|
139
|
+
# @return [Boolean] true if no headers exist
|
|
140
|
+
# @example
|
|
141
|
+
# headers.empty? # => false
|
|
142
|
+
def empty?
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Remove all headers.
|
|
146
|
+
#
|
|
147
|
+
# @return [void]
|
|
148
|
+
# @example
|
|
149
|
+
# headers.clear
|
|
150
|
+
# headers.empty? # => true
|
|
151
|
+
def clear
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Get all header names.
|
|
155
|
+
#
|
|
156
|
+
# @return [Array<String>] Array of header names (lowercase)
|
|
157
|
+
# @example
|
|
158
|
+
# headers.keys
|
|
159
|
+
# # => ["content-type", "accept", "user-agent", "authorization"]
|
|
160
|
+
def keys
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Get all header values.
|
|
164
|
+
#
|
|
165
|
+
# Returns one value per header (the first if multiple values exist).
|
|
166
|
+
#
|
|
167
|
+
# @return [Array<String>] Array of header values
|
|
168
|
+
# @example
|
|
169
|
+
# headers.values
|
|
170
|
+
# # => ["application/json", "text/html", "Mozilla/5.0", "Bearer token"]
|
|
171
|
+
def values
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Iterate over headers.
|
|
175
|
+
#
|
|
176
|
+
# Yields each header name and value pair. If a header has multiple values,
|
|
177
|
+
# only the first is yielded.
|
|
178
|
+
#
|
|
179
|
+
# @yieldparam name [String] Header name (lowercase)
|
|
180
|
+
# @yieldparam value [String] Header value
|
|
181
|
+
# @return [Enumerator, self] Returns enumerator if no block given, self otherwise
|
|
182
|
+
# @example With block
|
|
183
|
+
# headers.each do |name, value|
|
|
184
|
+
# puts "#{name}: #{value}"
|
|
185
|
+
# end
|
|
186
|
+
# @example Without block
|
|
187
|
+
# enum = headers.each
|
|
188
|
+
# enum.to_a # => [["content-type", "text/html"], ...]
|
|
189
|
+
def each
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Convert headers to a string representation.
|
|
193
|
+
def to_s
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wreq
|
|
4
|
+
# HTTP method enumeration backed by Rust.
|
|
5
|
+
#
|
|
6
|
+
# Variants are exposed as constants under this class.
|
|
7
|
+
# Each constant is an instance of {Wreq::Method}.
|
|
8
|
+
#
|
|
9
|
+
# @example Using predefined constants
|
|
10
|
+
# method = Wreq::Method::GET
|
|
11
|
+
# method.class #=> Wreq::Method
|
|
12
|
+
#
|
|
13
|
+
# @example In request context
|
|
14
|
+
# Wreq.request(url: "https://api.example.com", method: Wreq::Method::POST)
|
|
15
|
+
class Method
|
|
16
|
+
# Constants are set by the native extension at initialization.
|
|
17
|
+
# These stubs are for documentation only.
|
|
18
|
+
unless const_defined?(:GET)
|
|
19
|
+
GET = nil # @return [Wreq::Method] HTTP GET method
|
|
20
|
+
HEAD = nil # @return [Wreq::Method] HTTP HEAD method
|
|
21
|
+
POST = nil # @return [Wreq::Method] HTTP POST method
|
|
22
|
+
PUT = nil # @return [Wreq::Method] HTTP PUT method
|
|
23
|
+
DELETE = nil # @return [Wreq::Method] HTTP DELETE method
|
|
24
|
+
OPTIONS = nil # @return [Wreq::Method] HTTP OPTIONS method
|
|
25
|
+
TRACE = nil # @return [Wreq::Method] HTTP TRACE method
|
|
26
|
+
PATCH = nil # @return [Wreq::Method] HTTP PATCH method
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# HTTP version enumeration backed by Rust.
|
|
31
|
+
#
|
|
32
|
+
# @example Using predefined constants
|
|
33
|
+
# version = Wreq::Version::HTTP_11
|
|
34
|
+
# version.class #=> Wreq::Version
|
|
35
|
+
class Version
|
|
36
|
+
# Constants are set by the native extension at initialization.
|
|
37
|
+
# These stubs are for documentation only.
|
|
38
|
+
unless const_defined?(:HTTP_11)
|
|
39
|
+
HTTP_09 = nil # @return [Wreq::Version] HTTP/0.9
|
|
40
|
+
HTTP_10 = nil # @return [Wreq::Version] HTTP/1.0
|
|
41
|
+
HTTP_11 = nil # @return [Wreq::Version] HTTP/1.1
|
|
42
|
+
HTTP_2 = nil # @return [Wreq::Version] HTTP/2
|
|
43
|
+
HTTP_3 = nil # @return [Wreq::Version] HTTP/3
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns a string representation of the HTTP version.
|
|
47
|
+
# @return [String] HTTP version as string
|
|
48
|
+
unless method_defined?(:to_s)
|
|
49
|
+
def to_s
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# HTTP status code wrapper.
|
|
55
|
+
#
|
|
56
|
+
# This class wraps standard HTTP status codes and provides
|
|
57
|
+
# convenient methods to check the response category.
|
|
58
|
+
#
|
|
59
|
+
# The actual implementation is provided by Rust for performance.
|
|
60
|
+
#
|
|
61
|
+
# @example Check if response is successful
|
|
62
|
+
# status = response.status
|
|
63
|
+
# if status.success?
|
|
64
|
+
# puts "Request succeeded with code: #{status.as_int}"
|
|
65
|
+
# end
|
|
66
|
+
#
|
|
67
|
+
# @example Check different status categories
|
|
68
|
+
# status.informational? # 1xx
|
|
69
|
+
# status.success? # 2xx
|
|
70
|
+
# status.redirection? # 3xx
|
|
71
|
+
# status.client_error? # 4xx
|
|
72
|
+
# status.server_error? # 5xx
|
|
73
|
+
unless const_defined?(:StatusCode)
|
|
74
|
+
class StatusCode
|
|
75
|
+
# Returns the status code as an integer.
|
|
76
|
+
#
|
|
77
|
+
# @return [Integer] the numeric HTTP status code (100-599)
|
|
78
|
+
def as_int
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Checks if status code is informational (1xx).
|
|
82
|
+
#
|
|
83
|
+
# Informational responses indicate that the request was received
|
|
84
|
+
# and the process is continuing.
|
|
85
|
+
#
|
|
86
|
+
# @return [Boolean] true if status is 100-199
|
|
87
|
+
def informational?
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Checks if status code indicates success (2xx).
|
|
91
|
+
#
|
|
92
|
+
# Success responses indicate that the request was successfully
|
|
93
|
+
# received, understood, and accepted.
|
|
94
|
+
#
|
|
95
|
+
# @return [Boolean] true if status is 200-299
|
|
96
|
+
def success?
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Checks if status code indicates redirection (3xx).
|
|
100
|
+
#
|
|
101
|
+
# Redirection responses indicate that further action needs to be
|
|
102
|
+
# taken to complete the request.
|
|
103
|
+
#
|
|
104
|
+
# @return [Boolean] true if status is 300-399
|
|
105
|
+
def redirection?
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Checks if status code indicates client error (4xx).
|
|
109
|
+
#
|
|
110
|
+
# Client error responses indicate that the request contains bad
|
|
111
|
+
# syntax or cannot be fulfilled.
|
|
112
|
+
#
|
|
113
|
+
# @return [Boolean] true if status is 400-499
|
|
114
|
+
def client_error?
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Checks if status code indicates server error (5xx).
|
|
118
|
+
#
|
|
119
|
+
# Server error responses indicate that the server failed to
|
|
120
|
+
# fulfill a valid request.
|
|
121
|
+
#
|
|
122
|
+
# @return [Boolean] true if status is 500-599
|
|
123
|
+
def server_error?
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Returns a string representation of the status code.
|
|
127
|
+
# @return [String] Status code as string
|
|
128
|
+
def to_s
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|