httparty 0.20.0 → 0.24.2
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/.github/dependabot.yml +6 -0
- data/.github/workflows/ci.yml +6 -5
- data/.gitignore +2 -1
- data/Changelog.md +388 -315
- data/Gemfile +3 -0
- data/Guardfile +3 -2
- data/README.md +17 -17
- data/docs/README.md +57 -5
- data/examples/README.md +1 -0
- data/examples/multipart.rb +13 -0
- data/examples/party_foul_mode.rb +90 -0
- data/httparty.gemspec +4 -2
- data/lib/httparty/connection_adapter.rb +5 -24
- data/lib/httparty/decompressor.rb +11 -1
- data/lib/httparty/exceptions.rb +34 -3
- data/lib/httparty/logger/curl_formatter.rb +1 -1
- data/lib/httparty/logger/logstash_formatter.rb +1 -0
- data/lib/httparty/module_inheritable_attributes.rb +3 -5
- data/lib/httparty/parser.rb +3 -0
- data/lib/httparty/request/body.rb +40 -13
- data/lib/httparty/request/streaming_multipart_body.rb +190 -0
- data/lib/httparty/request.rb +89 -37
- data/lib/httparty/response.rb +3 -3
- data/lib/httparty/text_encoder.rb +1 -1
- data/lib/httparty/version.rb +1 -1
- data/lib/httparty.rb +24 -12
- data/script/release +4 -4
- metadata +30 -13
- data/.simplecov +0 -1
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTParty
|
|
4
|
+
class Request
|
|
5
|
+
class StreamingMultipartBody
|
|
6
|
+
NEWLINE = "\r\n"
|
|
7
|
+
CHUNK_SIZE = 64 * 1024 # 64 KB chunks
|
|
8
|
+
|
|
9
|
+
def initialize(parts, boundary)
|
|
10
|
+
@parts = parts
|
|
11
|
+
@boundary = boundary
|
|
12
|
+
@part_index = 0
|
|
13
|
+
@state = :header
|
|
14
|
+
@current_file = nil
|
|
15
|
+
@header_buffer = nil
|
|
16
|
+
@header_offset = 0
|
|
17
|
+
@footer_sent = false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def size
|
|
21
|
+
@size ||= calculate_size
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def read(length = nil, outbuf = nil)
|
|
25
|
+
outbuf = outbuf ? outbuf.replace(''.b) : ''.b
|
|
26
|
+
|
|
27
|
+
return read_all(outbuf) if length.nil?
|
|
28
|
+
|
|
29
|
+
while outbuf.bytesize < length
|
|
30
|
+
chunk = read_chunk(length - outbuf.bytesize)
|
|
31
|
+
break if chunk.nil?
|
|
32
|
+
outbuf << chunk
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
outbuf.empty? ? nil : outbuf
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def rewind
|
|
39
|
+
@part_index = 0
|
|
40
|
+
@state = :header
|
|
41
|
+
@current_file = nil
|
|
42
|
+
@header_buffer = nil
|
|
43
|
+
@header_offset = 0
|
|
44
|
+
@footer_sent = false
|
|
45
|
+
@parts.each do |_key, value, _is_file|
|
|
46
|
+
value.rewind if value.respond_to?(:rewind)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def read_all(outbuf)
|
|
53
|
+
while (chunk = read_chunk(CHUNK_SIZE))
|
|
54
|
+
outbuf << chunk
|
|
55
|
+
end
|
|
56
|
+
outbuf.empty? ? nil : outbuf
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def read_chunk(max_length)
|
|
60
|
+
loop do
|
|
61
|
+
return nil if @part_index >= @parts.size && @footer_sent
|
|
62
|
+
|
|
63
|
+
if @part_index >= @parts.size
|
|
64
|
+
@footer_sent = true
|
|
65
|
+
return "--#{@boundary}--#{NEWLINE}".b
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
key, value, is_file = @parts[@part_index]
|
|
69
|
+
|
|
70
|
+
case @state
|
|
71
|
+
when :header
|
|
72
|
+
chunk = read_header_chunk(key, value, is_file, max_length)
|
|
73
|
+
return chunk if chunk
|
|
74
|
+
|
|
75
|
+
when :body
|
|
76
|
+
chunk = read_body_chunk(value, is_file, max_length)
|
|
77
|
+
return chunk if chunk
|
|
78
|
+
|
|
79
|
+
when :newline
|
|
80
|
+
@state = :header
|
|
81
|
+
@part_index += 1
|
|
82
|
+
return NEWLINE.b
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def read_header_chunk(key, value, is_file, max_length)
|
|
88
|
+
if @header_buffer.nil?
|
|
89
|
+
@header_buffer = build_part_header(key, value, is_file)
|
|
90
|
+
@header_offset = 0
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
remaining = @header_buffer.bytesize - @header_offset
|
|
94
|
+
if remaining > 0
|
|
95
|
+
chunk_size = [remaining, max_length].min
|
|
96
|
+
chunk = @header_buffer.byteslice(@header_offset, chunk_size)
|
|
97
|
+
@header_offset += chunk_size
|
|
98
|
+
return chunk
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
@header_buffer = nil
|
|
102
|
+
@header_offset = 0
|
|
103
|
+
@state = :body
|
|
104
|
+
nil
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def read_body_chunk(value, is_file, max_length)
|
|
108
|
+
if is_file
|
|
109
|
+
chunk = read_file_chunk(value, max_length)
|
|
110
|
+
if chunk
|
|
111
|
+
return chunk
|
|
112
|
+
else
|
|
113
|
+
@current_file = nil
|
|
114
|
+
@state = :newline
|
|
115
|
+
return nil
|
|
116
|
+
end
|
|
117
|
+
else
|
|
118
|
+
@state = :newline
|
|
119
|
+
return value.to_s.b
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def read_file_chunk(file, max_length)
|
|
124
|
+
chunk_size = [max_length, CHUNK_SIZE].min
|
|
125
|
+
chunk = file.read(chunk_size)
|
|
126
|
+
return nil if chunk.nil?
|
|
127
|
+
chunk.force_encoding(Encoding::BINARY) if chunk.respond_to?(:force_encoding)
|
|
128
|
+
chunk
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def build_part_header(key, value, is_file)
|
|
132
|
+
header = "--#{@boundary}#{NEWLINE}".b
|
|
133
|
+
header << %(Content-Disposition: form-data; name="#{key}").b
|
|
134
|
+
if is_file
|
|
135
|
+
header << %(; filename="#{file_name(value).gsub(/["\r\n]/, replacement_table)}").b
|
|
136
|
+
header << NEWLINE.b
|
|
137
|
+
header << "Content-Type: #{content_type(value)}#{NEWLINE}".b
|
|
138
|
+
else
|
|
139
|
+
header << NEWLINE.b
|
|
140
|
+
end
|
|
141
|
+
header << NEWLINE.b
|
|
142
|
+
header
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def calculate_size
|
|
146
|
+
total = 0
|
|
147
|
+
@parts.each do |key, value, is_file|
|
|
148
|
+
total += build_part_header(key, value, is_file).bytesize
|
|
149
|
+
total += content_size(value, is_file)
|
|
150
|
+
total += NEWLINE.bytesize
|
|
151
|
+
end
|
|
152
|
+
total += "--#{@boundary}--#{NEWLINE}".bytesize
|
|
153
|
+
total
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def content_size(value, is_file)
|
|
157
|
+
if is_file
|
|
158
|
+
if value.respond_to?(:size)
|
|
159
|
+
value.size
|
|
160
|
+
elsif value.respond_to?(:stat)
|
|
161
|
+
value.stat.size
|
|
162
|
+
else
|
|
163
|
+
value.read.bytesize.tap { value.rewind }
|
|
164
|
+
end
|
|
165
|
+
else
|
|
166
|
+
value.to_s.b.bytesize
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def content_type(object)
|
|
171
|
+
return object.content_type if object.respond_to?(:content_type)
|
|
172
|
+
require 'mini_mime'
|
|
173
|
+
mime = MiniMime.lookup_by_filename(object.path)
|
|
174
|
+
mime ? mime.content_type : 'application/octet-stream'
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def file_name(object)
|
|
178
|
+
object.respond_to?(:original_filename) ? object.original_filename : File.basename(object.path)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def replacement_table
|
|
182
|
+
@replacement_table ||= {
|
|
183
|
+
'"' => '%22',
|
|
184
|
+
"\r" => '%0D',
|
|
185
|
+
"\n" => '%0A'
|
|
186
|
+
}.freeze
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
data/lib/httparty/request.rb
CHANGED
|
@@ -47,8 +47,12 @@ module HTTParty
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def self._load(data)
|
|
50
|
-
http_method, path, options = Marshal.load(data)
|
|
51
|
-
new(http_method, path, options)
|
|
50
|
+
http_method, path, options, last_response, last_uri, raw_request = Marshal.load(data)
|
|
51
|
+
instance = new(http_method, path, options)
|
|
52
|
+
instance.last_response = last_response
|
|
53
|
+
instance.last_uri = last_uri
|
|
54
|
+
instance.instance_variable_set("@raw_request", raw_request)
|
|
55
|
+
instance
|
|
52
56
|
end
|
|
53
57
|
|
|
54
58
|
attr_accessor :http_method, :options, :last_response, :redirect, :last_uri
|
|
@@ -109,6 +113,8 @@ module HTTParty
|
|
|
109
113
|
new_uri = path.clone
|
|
110
114
|
end
|
|
111
115
|
|
|
116
|
+
validate_uri_safety!(new_uri) unless redirect
|
|
117
|
+
|
|
112
118
|
# avoid double query string on redirects [#12]
|
|
113
119
|
unless redirect
|
|
114
120
|
new_uri.query = query_string(new_uri)
|
|
@@ -149,24 +155,28 @@ module HTTParty
|
|
|
149
155
|
chunked_body = nil
|
|
150
156
|
current_http = http
|
|
151
157
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
158
|
+
begin
|
|
159
|
+
self.last_response = current_http.request(@raw_request) do |http_response|
|
|
160
|
+
if block
|
|
161
|
+
chunks = []
|
|
155
162
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
163
|
+
http_response.read_body do |fragment|
|
|
164
|
+
encoded_fragment = encode_text(fragment, http_response['content-type'])
|
|
165
|
+
chunks << encoded_fragment if !options[:stream_body]
|
|
166
|
+
block.call ResponseFragment.new(encoded_fragment, http_response, current_http)
|
|
167
|
+
end
|
|
161
168
|
|
|
162
|
-
|
|
169
|
+
chunked_body = chunks.join
|
|
170
|
+
end
|
|
163
171
|
end
|
|
164
|
-
end
|
|
165
172
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
173
|
+
handle_host_redirection if response_redirects?
|
|
174
|
+
result = handle_unauthorized
|
|
175
|
+
result ||= handle_response(chunked_body, &block)
|
|
176
|
+
result
|
|
177
|
+
rescue *COMMON_NETWORK_ERRORS => e
|
|
178
|
+
raise options[:foul] ? HTTParty::NetworkError.new("#{e.class}: #{e.message}") : e
|
|
179
|
+
end
|
|
170
180
|
end
|
|
171
181
|
|
|
172
182
|
def handle_unauthorized(&block)
|
|
@@ -184,7 +194,7 @@ module HTTParty
|
|
|
184
194
|
opts = options.dup
|
|
185
195
|
opts.delete(:logger)
|
|
186
196
|
opts.delete(:parser) if opts[:parser] && opts[:parser].is_a?(Proc)
|
|
187
|
-
Marshal.dump([http_method, path, opts])
|
|
197
|
+
Marshal.dump([http_method, path, opts, last_response, @last_uri, @raw_request])
|
|
188
198
|
end
|
|
189
199
|
|
|
190
200
|
private
|
|
@@ -237,8 +247,17 @@ module HTTParty
|
|
|
237
247
|
if body.multipart?
|
|
238
248
|
content_type = "multipart/form-data; boundary=#{body.boundary}"
|
|
239
249
|
@raw_request['Content-Type'] = content_type
|
|
250
|
+
elsif options[:body].respond_to?(:to_hash) && !@raw_request['Content-Type']
|
|
251
|
+
@raw_request['Content-Type'] = 'application/x-www-form-urlencoded'
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
if body.streaming? && options[:stream_body] == true
|
|
255
|
+
stream = body.to_stream
|
|
256
|
+
@raw_request.body_stream = stream
|
|
257
|
+
@raw_request['Content-Length'] = stream.size.to_s
|
|
258
|
+
else
|
|
259
|
+
@raw_request.body = body.call
|
|
240
260
|
end
|
|
241
|
-
@raw_request.body = body.call
|
|
242
261
|
end
|
|
243
262
|
|
|
244
263
|
@raw_request.instance_variable_set(:@decode_content, decompress_content?)
|
|
@@ -291,24 +310,7 @@ module HTTParty
|
|
|
291
310
|
|
|
292
311
|
def handle_response(raw_body, &block)
|
|
293
312
|
if response_redirects?
|
|
294
|
-
|
|
295
|
-
if options[:logger]
|
|
296
|
-
logger = HTTParty::Logger.build(options[:logger], options[:log_level], options[:log_format])
|
|
297
|
-
logger.format(self, last_response)
|
|
298
|
-
end
|
|
299
|
-
self.path = last_response['location']
|
|
300
|
-
self.redirect = true
|
|
301
|
-
if last_response.class == Net::HTTPSeeOther
|
|
302
|
-
unless options[:maintain_method_across_redirects] && options[:resend_on_redirect]
|
|
303
|
-
self.http_method = Net::HTTP::Get
|
|
304
|
-
end
|
|
305
|
-
elsif last_response.code != '307' && last_response.code != '308'
|
|
306
|
-
unless options[:maintain_method_across_redirects]
|
|
307
|
-
self.http_method = Net::HTTP::Get
|
|
308
|
-
end
|
|
309
|
-
end
|
|
310
|
-
capture_cookies(last_response)
|
|
311
|
-
perform(&block)
|
|
313
|
+
handle_redirection(&block)
|
|
312
314
|
else
|
|
313
315
|
raw_body ||= last_response.body
|
|
314
316
|
|
|
@@ -327,10 +329,34 @@ module HTTParty
|
|
|
327
329
|
end
|
|
328
330
|
end
|
|
329
331
|
|
|
332
|
+
def handle_redirection(&block)
|
|
333
|
+
options[:limit] -= 1
|
|
334
|
+
if options[:logger]
|
|
335
|
+
logger = HTTParty::Logger.build(options[:logger], options[:log_level], options[:log_format])
|
|
336
|
+
logger.format(self, last_response)
|
|
337
|
+
end
|
|
338
|
+
self.path = last_response['location']
|
|
339
|
+
self.redirect = true
|
|
340
|
+
if last_response.class == Net::HTTPSeeOther
|
|
341
|
+
unless options[:maintain_method_across_redirects] && options[:resend_on_redirect]
|
|
342
|
+
self.http_method = Net::HTTP::Get
|
|
343
|
+
end
|
|
344
|
+
elsif last_response.code != '307' && last_response.code != '308'
|
|
345
|
+
unless options[:maintain_method_across_redirects]
|
|
346
|
+
self.http_method = Net::HTTP::Get
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
if http_method == Net::HTTP::Get
|
|
350
|
+
clear_body
|
|
351
|
+
end
|
|
352
|
+
capture_cookies(last_response)
|
|
353
|
+
perform(&block)
|
|
354
|
+
end
|
|
355
|
+
|
|
330
356
|
def handle_host_redirection
|
|
331
357
|
check_duplicate_location_header
|
|
332
358
|
redirect_path = options[:uri_adapter].parse(last_response['location']).normalize
|
|
333
|
-
return if redirect_path.relative? || path.host == redirect_path.host
|
|
359
|
+
return if redirect_path.relative? || path.host == redirect_path.host || uri.host == redirect_path.host
|
|
334
360
|
@changed_hosts = true
|
|
335
361
|
end
|
|
336
362
|
|
|
@@ -358,6 +384,14 @@ module HTTParty
|
|
|
358
384
|
parser.call(body, format)
|
|
359
385
|
end
|
|
360
386
|
|
|
387
|
+
# Some Web Application Firewalls reject incoming GET requests that have a body
|
|
388
|
+
# if we redirect, and the resulting verb is GET then we will clear the body that
|
|
389
|
+
# may be left behind from the initiating request
|
|
390
|
+
def clear_body
|
|
391
|
+
options[:body] = nil
|
|
392
|
+
@raw_request.body = nil
|
|
393
|
+
end
|
|
394
|
+
|
|
361
395
|
def capture_cookies(response)
|
|
362
396
|
return unless response['Set-Cookie']
|
|
363
397
|
cookies_hash = HTTParty::CookieHash.new
|
|
@@ -410,5 +444,23 @@ module HTTParty
|
|
|
410
444
|
assume_utf16_is_big_endian: assume_utf16_is_big_endian
|
|
411
445
|
).call
|
|
412
446
|
end
|
|
447
|
+
|
|
448
|
+
def validate_uri_safety!(new_uri)
|
|
449
|
+
return if options[:skip_uri_validation]
|
|
450
|
+
|
|
451
|
+
configured_base_uri = options[:base_uri]
|
|
452
|
+
return unless configured_base_uri
|
|
453
|
+
|
|
454
|
+
normalized_base = options[:uri_adapter].parse(
|
|
455
|
+
HTTParty.normalize_base_uri(configured_base_uri)
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
return if new_uri.host == normalized_base.host
|
|
459
|
+
|
|
460
|
+
raise UnsafeURIError,
|
|
461
|
+
"Requested URI '#{new_uri}' has host '#{new_uri.host}' but the " \
|
|
462
|
+
"configured base_uri '#{normalized_base}' has host '#{normalized_base.host}'. " \
|
|
463
|
+
"This request could send credentials to an unintended server."
|
|
464
|
+
end
|
|
413
465
|
end
|
|
414
466
|
end
|
data/lib/httparty/response.rb
CHANGED
|
@@ -67,12 +67,12 @@ module HTTParty
|
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
# Support old multiple_choice? method from pre 2.0.0 era.
|
|
70
|
-
if ::
|
|
70
|
+
if ::RUBY_PLATFORM != 'java'
|
|
71
71
|
alias_method :multiple_choice?, :multiple_choices?
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
# Support old status codes method from pre 2.6.0 era.
|
|
75
|
-
if ::
|
|
75
|
+
if ::RUBY_PLATFORM != 'java'
|
|
76
76
|
alias_method :gateway_time_out?, :gateway_timeout?
|
|
77
77
|
alias_method :request_entity_too_large?, :payload_too_large?
|
|
78
78
|
alias_method :request_time_out?, :request_timeout?
|
|
@@ -133,7 +133,7 @@ module HTTParty
|
|
|
133
133
|
end
|
|
134
134
|
|
|
135
135
|
def throw_exception
|
|
136
|
-
if @request.options[:raise_on]
|
|
136
|
+
if @request.options[:raise_on].to_a.detect { |c| code.to_s.match(/#{c.to_s}/) }
|
|
137
137
|
::Kernel.raise ::HTTParty::ResponseError.new(@response), "Code #{code} - #{body}"
|
|
138
138
|
end
|
|
139
139
|
end
|
|
@@ -5,7 +5,7 @@ module HTTParty
|
|
|
5
5
|
attr_reader :text, :content_type, :assume_utf16_is_big_endian
|
|
6
6
|
|
|
7
7
|
def initialize(text, assume_utf16_is_big_endian: true, content_type: nil)
|
|
8
|
-
@text = text
|
|
8
|
+
@text = +text
|
|
9
9
|
@content_type = content_type
|
|
10
10
|
@assume_utf16_is_big_endian = assume_utf16_is_big_endian
|
|
11
11
|
end
|
data/lib/httparty/version.rb
CHANGED
data/lib/httparty.rb
CHANGED
|
@@ -2,13 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'pathname'
|
|
4
4
|
require 'net/http'
|
|
5
|
-
require 'net/https'
|
|
6
5
|
require 'uri'
|
|
7
|
-
require 'zlib'
|
|
8
|
-
require 'multi_xml'
|
|
9
|
-
require 'mime/types'
|
|
10
|
-
require 'json'
|
|
11
|
-
require 'csv'
|
|
12
6
|
|
|
13
7
|
require 'httparty/module_inheritable_attributes'
|
|
14
8
|
require 'httparty/cookie_hash'
|
|
@@ -47,7 +41,7 @@ module HTTParty
|
|
|
47
41
|
# [:+local_host+:] Local address to bind to before connecting.
|
|
48
42
|
# [:+local_port+:] Local port to bind to before connecting.
|
|
49
43
|
# [:+body_stream+:] Allow streaming to a REST server to specify a body_stream.
|
|
50
|
-
# [:+stream_body+:]
|
|
44
|
+
# [:+stream_body+:] When downloading with a block, avoids accumulating the response in memory. When uploading files, streams the request body to reduce memory usage (opt-in).
|
|
51
45
|
# [:+multipart+:] Force content-type to be multipart
|
|
52
46
|
#
|
|
53
47
|
# There are also another set of options with names corresponding to various class methods. The methods in question are those that let you set a class-wide default, and the options override the defaults on a request-by-request basis. Those options are:
|
|
@@ -68,6 +62,16 @@ module HTTParty
|
|
|
68
62
|
# * :+ssl_ca_path+: see HTTParty::ClassMethods.ssl_ca_path.
|
|
69
63
|
|
|
70
64
|
module ClassMethods
|
|
65
|
+
# Turns on or off the foul option.
|
|
66
|
+
#
|
|
67
|
+
# class Foo
|
|
68
|
+
# include HTTParty
|
|
69
|
+
# foul true
|
|
70
|
+
# end
|
|
71
|
+
def foul(bool)
|
|
72
|
+
default_options[:foul] = bool
|
|
73
|
+
end
|
|
74
|
+
|
|
71
75
|
# Turns on logging
|
|
72
76
|
#
|
|
73
77
|
# class Foo
|
|
@@ -84,7 +88,7 @@ module HTTParty
|
|
|
84
88
|
#
|
|
85
89
|
# class Foo
|
|
86
90
|
# include HTTParty
|
|
87
|
-
# raise_on [404, 500]
|
|
91
|
+
# raise_on [404, 500, '5[0-9]*']
|
|
88
92
|
# end
|
|
89
93
|
def raise_on(codes = [])
|
|
90
94
|
default_options[:raise_on] = *codes
|
|
@@ -592,6 +596,13 @@ module HTTParty
|
|
|
592
596
|
perform_request Net::HTTP::Unlock, path, options, &block
|
|
593
597
|
end
|
|
594
598
|
|
|
599
|
+
def build_request(http_method, path, options = {})
|
|
600
|
+
options = ModuleInheritableAttributes.hash_deep_dup(default_options).merge(options)
|
|
601
|
+
HeadersProcessor.new(headers, options).call
|
|
602
|
+
process_cookies(options)
|
|
603
|
+
Request.new(http_method, path, options)
|
|
604
|
+
end
|
|
605
|
+
|
|
595
606
|
attr_reader :default_options
|
|
596
607
|
|
|
597
608
|
private
|
|
@@ -607,10 +618,7 @@ module HTTParty
|
|
|
607
618
|
end
|
|
608
619
|
|
|
609
620
|
def perform_request(http_method, path, options, &block) #:nodoc:
|
|
610
|
-
|
|
611
|
-
HeadersProcessor.new(headers, options).call
|
|
612
|
-
process_cookies(options)
|
|
613
|
-
Request.new(http_method, path, options).perform(&block)
|
|
621
|
+
build_request(http_method, path, options).perform(&block)
|
|
614
622
|
end
|
|
615
623
|
|
|
616
624
|
def process_cookies(options) #:nodoc:
|
|
@@ -677,6 +685,10 @@ module HTTParty
|
|
|
677
685
|
def self.options(*args, &block)
|
|
678
686
|
Basement.options(*args, &block)
|
|
679
687
|
end
|
|
688
|
+
|
|
689
|
+
def self.build_request(*args, &block)
|
|
690
|
+
Basement.build_request(*args, &block)
|
|
691
|
+
end
|
|
680
692
|
end
|
|
681
693
|
|
|
682
694
|
require 'httparty/hash_conversions'
|
data/script/release
CHANGED
|
@@ -18,9 +18,9 @@ gem_name=httparty
|
|
|
18
18
|
rm -rf $gem_name-*.gem
|
|
19
19
|
gem build -q $gem_name.gemspec
|
|
20
20
|
|
|
21
|
-
# Make sure we're on the
|
|
22
|
-
(git branch | grep -q '*
|
|
23
|
-
echo "Only release from the
|
|
21
|
+
# Make sure we're on the main branch.
|
|
22
|
+
(git branch | grep -q '* main') || {
|
|
23
|
+
echo "Only release from the main branch."
|
|
24
24
|
exit 1
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -39,4 +39,4 @@ git fetch -t origin
|
|
|
39
39
|
|
|
40
40
|
# Tag it and bag it.
|
|
41
41
|
gem push $gem_name-*.gem && git tag "$tag" &&
|
|
42
|
-
git push origin
|
|
42
|
+
git push origin main && git push origin "$tag"
|
metadata
CHANGED
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: httparty
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.24.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- John Nunemaker
|
|
8
8
|
- Sandro Turriate
|
|
9
|
-
autorequire:
|
|
9
|
+
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
12
|
+
date: 2026-01-14 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: csv
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
requirements:
|
|
18
|
+
- - ">="
|
|
19
|
+
- !ruby/object:Gem::Version
|
|
20
|
+
version: '0'
|
|
21
|
+
type: :runtime
|
|
22
|
+
prerelease: false
|
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
24
|
+
requirements:
|
|
25
|
+
- - ">="
|
|
26
|
+
- !ruby/object:Gem::Version
|
|
27
|
+
version: '0'
|
|
14
28
|
- !ruby/object:Gem::Dependency
|
|
15
29
|
name: multi_xml
|
|
16
30
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -26,19 +40,19 @@ dependencies:
|
|
|
26
40
|
- !ruby/object:Gem::Version
|
|
27
41
|
version: 0.5.2
|
|
28
42
|
- !ruby/object:Gem::Dependency
|
|
29
|
-
name:
|
|
43
|
+
name: mini_mime
|
|
30
44
|
requirement: !ruby/object:Gem::Requirement
|
|
31
45
|
requirements:
|
|
32
|
-
- - "
|
|
46
|
+
- - ">="
|
|
33
47
|
- !ruby/object:Gem::Version
|
|
34
|
-
version:
|
|
48
|
+
version: 1.0.0
|
|
35
49
|
type: :runtime
|
|
36
50
|
prerelease: false
|
|
37
51
|
version_requirements: !ruby/object:Gem::Requirement
|
|
38
52
|
requirements:
|
|
39
|
-
- - "
|
|
53
|
+
- - ">="
|
|
40
54
|
- !ruby/object:Gem::Version
|
|
41
|
-
version:
|
|
55
|
+
version: 1.0.0
|
|
42
56
|
description: Makes http fun! Also, makes consuming restful web services dead easy.
|
|
43
57
|
email:
|
|
44
58
|
- nunemaker@gmail.com
|
|
@@ -48,11 +62,11 @@ extensions: []
|
|
|
48
62
|
extra_rdoc_files: []
|
|
49
63
|
files:
|
|
50
64
|
- ".editorconfig"
|
|
65
|
+
- ".github/dependabot.yml"
|
|
51
66
|
- ".github/workflows/ci.yml"
|
|
52
67
|
- ".gitignore"
|
|
53
68
|
- ".rubocop.yml"
|
|
54
69
|
- ".rubocop_todo.yml"
|
|
55
|
-
- ".simplecov"
|
|
56
70
|
- CONTRIBUTING.md
|
|
57
71
|
- Changelog.md
|
|
58
72
|
- Gemfile
|
|
@@ -77,6 +91,7 @@ files:
|
|
|
77
91
|
- examples/microsoft_graph.rb
|
|
78
92
|
- examples/multipart.rb
|
|
79
93
|
- examples/nokogiri_html_parser.rb
|
|
94
|
+
- examples/party_foul_mode.rb
|
|
80
95
|
- examples/peer_cert.rb
|
|
81
96
|
- examples/rescue_json.rb
|
|
82
97
|
- examples/rubyurl.rb
|
|
@@ -103,6 +118,7 @@ files:
|
|
|
103
118
|
- lib/httparty/request.rb
|
|
104
119
|
- lib/httparty/request/body.rb
|
|
105
120
|
- lib/httparty/request/multipart_boundary.rb
|
|
121
|
+
- lib/httparty/request/streaming_multipart_body.rb
|
|
106
122
|
- lib/httparty/response.rb
|
|
107
123
|
- lib/httparty/response/headers.rb
|
|
108
124
|
- lib/httparty/response_fragment.rb
|
|
@@ -115,7 +131,8 @@ files:
|
|
|
115
131
|
homepage: https://github.com/jnunemaker/httparty
|
|
116
132
|
licenses:
|
|
117
133
|
- MIT
|
|
118
|
-
metadata:
|
|
134
|
+
metadata:
|
|
135
|
+
changelog_uri: https://github.com/jnunemaker/httparty/releases
|
|
119
136
|
post_install_message: When you HTTParty, you must party hard!
|
|
120
137
|
rdoc_options: []
|
|
121
138
|
require_paths:
|
|
@@ -124,15 +141,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
124
141
|
requirements:
|
|
125
142
|
- - ">="
|
|
126
143
|
- !ruby/object:Gem::Version
|
|
127
|
-
version: 2.
|
|
144
|
+
version: 2.7.0
|
|
128
145
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
146
|
requirements:
|
|
130
147
|
- - ">="
|
|
131
148
|
- !ruby/object:Gem::Version
|
|
132
149
|
version: '0'
|
|
133
150
|
requirements: []
|
|
134
|
-
rubygems_version: 3.
|
|
135
|
-
signing_key:
|
|
151
|
+
rubygems_version: 3.3.7
|
|
152
|
+
signing_key:
|
|
136
153
|
specification_version: 4
|
|
137
154
|
summary: Makes http fun! Also, makes consuming restful web services dead easy.
|
|
138
155
|
test_files: []
|
data/.simplecov
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
SimpleCov.start "test_frameworks"
|