curb 0.8.5 → 1.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +579 -0
- data/Rakefile +85 -27
- data/doc.rb +48 -8
- data/ext/banned.h +32 -0
- data/ext/curb.c +563 -233
- data/ext/curb.h +19 -10
- data/ext/curb_easy.c +3229 -368
- data/ext/curb_easy.h +42 -0
- data/ext/curb_errors.c +117 -18
- data/ext/curb_errors.h +9 -5
- data/ext/curb_macros.h +33 -21
- data/ext/curb_multi.c +1904 -272
- data/ext/curb_multi.h +11 -3
- data/ext/curb_postfield.c +149 -77
- data/ext/curb_postfield.h +1 -0
- data/ext/curb_upload.c +38 -11
- data/ext/curb_upload.h +2 -0
- data/ext/extconf.rb +355 -35
- data/lib/curb.rb +1 -0
- data/lib/curl/download.rb +160 -0
- data/lib/curl/easy.rb +422 -88
- data/lib/curl/multi.rb +295 -56
- data/lib/curl.rb +676 -11
- data/tests/bug_crash_on_debug.rb +14 -28
- data/tests/bug_crash_on_progress.rb +32 -16
- data/tests/bug_curb_easy_blocks_ruby_threads.rb +10 -15
- data/tests/bug_curb_easy_post_with_string_no_content_length_header.rb +6 -30
- data/tests/bug_follow_redirect_288.rb +83 -0
- data/tests/bug_instance_post_differs_from_class_post.rb +3 -5
- data/tests/bug_issue102.rb +17 -0
- data/tests/bug_issue_noproxy.rb +56 -0
- data/tests/bug_issue_post_redirect.rb +93 -0
- data/tests/bug_issue_spnego.rb +41 -0
- data/tests/bug_multi_segfault.rb +1 -0
- data/tests/bug_poison.rb +29 -0
- data/tests/bug_raise_on_callback.rb +30 -0
- data/tests/helper.rb +400 -44
- data/tests/leak_trace.rb +237 -0
- data/tests/mem_check.rb +3 -0
- data/tests/tc_curl.rb +31 -1
- data/tests/tc_curl_download.rb +98 -7
- data/tests/tc_curl_easy.rb +985 -66
- data/tests/tc_curl_easy_cookielist.rb +277 -0
- data/tests/tc_curl_easy_request_target.rb +41 -0
- data/tests/tc_curl_easy_resolve.rb +48 -0
- data/tests/tc_curl_maxfilesize.rb +212 -0
- data/tests/tc_curl_multi.rb +1111 -51
- data/tests/tc_curl_native_coverage.rb +145 -0
- data/tests/tc_curl_network_policy.rb +1475 -0
- data/tests/tc_curl_postfield.rb +207 -30
- data/tests/tc_curl_protocols.rb +388 -0
- data/tests/tc_fiber_scheduler.rb +584 -0
- data/tests/tc_ftp_options.rb +39 -0
- data/tests/tc_gc_compact.rb +223 -0
- data/tests/tc_test_server_methods.rb +110 -0
- data/tests/timeout.rb +30 -6
- metadata +66 -31
- data/README +0 -194
data/tests/tc_curl_easy.rb
CHANGED
|
@@ -4,6 +4,456 @@ class FooNoToS
|
|
|
4
4
|
end
|
|
5
5
|
|
|
6
6
|
class TestCurbCurlEasy < Test::Unit::TestCase
|
|
7
|
+
def test_global_reset
|
|
8
|
+
Curl.get($TEST_URL)
|
|
9
|
+
# in a Timeout block you should reset the thread current handle
|
|
10
|
+
Curl.reset
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_nested_easy_methods
|
|
14
|
+
easy = Curl.get(TestServlet.url) {|http|
|
|
15
|
+
res = Curl.get(TestServlet.url + '/not_here')
|
|
16
|
+
assert_equal 404, res.code
|
|
17
|
+
}
|
|
18
|
+
assert_equal 200, easy.code
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_perform_with_implicit_multi
|
|
22
|
+
easy = Curl::Easy.new($TEST_URL)
|
|
23
|
+
|
|
24
|
+
assert_nothing_raised { easy.perform }
|
|
25
|
+
assert_match(/^# DO NOT REMOVE THIS COMMENT/, easy.body_str)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_curlopt_resolve
|
|
29
|
+
require 'resolv'
|
|
30
|
+
uri = URI.parse(TestServlet.url)
|
|
31
|
+
resolved_ip = Resolv.getaddress(uri.host) # perform DNS lookup once
|
|
32
|
+
mapping = "#{uri.host}:#{uri.port}:#{resolved_ip}"
|
|
33
|
+
|
|
34
|
+
http = Curl::Easy.new(TestServlet.url)
|
|
35
|
+
http.setopt(Curl::CURLOPT_RESOLVE, [mapping])
|
|
36
|
+
|
|
37
|
+
http.get
|
|
38
|
+
|
|
39
|
+
assert_match(/GET/, http.body)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_resolve_clear_keeps_handle_usable
|
|
43
|
+
host = "curb.invalid"
|
|
44
|
+
url = "http://#{host}:#{TestServlet.port}#{TestServlet.path}"
|
|
45
|
+
mapping = "#{host}:#{TestServlet.port}:127.0.0.1"
|
|
46
|
+
|
|
47
|
+
http = Curl::Easy.new(url)
|
|
48
|
+
http.dns_cache_timeout = 0
|
|
49
|
+
http.resolve = [mapping]
|
|
50
|
+
http.get
|
|
51
|
+
assert_match(/GET/, http.body)
|
|
52
|
+
|
|
53
|
+
http.resolve = nil
|
|
54
|
+
http.url = TestServlet.url
|
|
55
|
+
http.get
|
|
56
|
+
assert_match(/GET/, http.body)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def test_curlopt_stderr_with_file
|
|
60
|
+
# does not work with Tempfile directly
|
|
61
|
+
path = Tempfile.new('curb_test_curlopt_stderr').path
|
|
62
|
+
File.open(path, 'w') do |file|
|
|
63
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
64
|
+
easy.verbose = true
|
|
65
|
+
easy.setopt(Curl::CURLOPT_STDERR, file)
|
|
66
|
+
easy.perform
|
|
67
|
+
end
|
|
68
|
+
output = File.read(path)
|
|
69
|
+
|
|
70
|
+
assert_match(/HTTP\/1\.1\ 200\ OK(?:\ )?/, output)
|
|
71
|
+
assert_match('Host: 127.0.0.1:9129', output)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def test_curlopt_stderr_with_io
|
|
75
|
+
tmp = Tempfile.new('curb_test_curlopt_stderr')
|
|
76
|
+
path = tmp.path
|
|
77
|
+
fd = IO.sysopen(path, 'w')
|
|
78
|
+
io = IO.new(fd, 'w')
|
|
79
|
+
io.sync = true
|
|
80
|
+
|
|
81
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
82
|
+
easy.verbose = true
|
|
83
|
+
easy.setopt(Curl::CURLOPT_STDERR, io)
|
|
84
|
+
easy.perform
|
|
85
|
+
|
|
86
|
+
io.flush
|
|
87
|
+
io.close
|
|
88
|
+
output = File.read(path)
|
|
89
|
+
|
|
90
|
+
assert_match(/HTTP\/1\.1\ 200\ OK(?:\ )?/, output)
|
|
91
|
+
assert_match('Host: 127.0.0.1:9129', output)
|
|
92
|
+
ensure
|
|
93
|
+
tmp.close! if defined?(tmp) && tmp
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def test_curlopt_stderr_gc_safe
|
|
97
|
+
tmp = Tempfile.new('curb_test_curlopt_stderr_gc')
|
|
98
|
+
path = tmp.path
|
|
99
|
+
fd = IO.sysopen(path, 'w')
|
|
100
|
+
io = IO.new(fd, 'w')
|
|
101
|
+
|
|
102
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
103
|
+
easy.verbose = true
|
|
104
|
+
easy.setopt(Curl::CURLOPT_STDERR, io)
|
|
105
|
+
|
|
106
|
+
# Drop our Ruby reference and force GC; curb should retain it internally
|
|
107
|
+
io = nil
|
|
108
|
+
GC.start
|
|
109
|
+
|
|
110
|
+
easy.perform
|
|
111
|
+
|
|
112
|
+
output = File.read(path)
|
|
113
|
+
assert_match(/HTTP\/1\.1\ 200\ OK(?:\ )?/, output)
|
|
114
|
+
assert_match('Host: 127.0.0.1:9129', output)
|
|
115
|
+
ensure
|
|
116
|
+
tmp.close! if defined?(tmp) && tmp
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def test_head_request_no_body_and_no_timeout
|
|
120
|
+
# Ensure a HEAD request completes and does not attempt to read a body
|
|
121
|
+
# even when the server advertises a Content-Length.
|
|
122
|
+
easy = nil
|
|
123
|
+
assert_nothing_raised do
|
|
124
|
+
easy = Curl.http(:HEAD, TestServlet.url)
|
|
125
|
+
end
|
|
126
|
+
assert_not_nil easy
|
|
127
|
+
# Header string should contain the HTTP status line.
|
|
128
|
+
assert_match(/HTTP\/1\.1\s\d+\s/, easy.header_str.to_s)
|
|
129
|
+
# Body should be empty for HEAD requests (libcurl won't call the write callback).
|
|
130
|
+
assert_equal "", easy.body_str.to_s
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def test_head_request_restores_easy_state_after_callback_exception
|
|
134
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
135
|
+
easy.on_complete { raise "head complete blew up" }
|
|
136
|
+
|
|
137
|
+
error = assert_raise(Curl::Err::AbortedByCallbackError) { easy.http("HEAD") }
|
|
138
|
+
assert_equal "head complete blew up", error.message
|
|
139
|
+
|
|
140
|
+
easy.on_complete { |_curl| }
|
|
141
|
+
easy.perform
|
|
142
|
+
|
|
143
|
+
assert_equal "GET", easy.body_str
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def test_patch_request_does_not_leak_custom_method_to_next_perform
|
|
147
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
148
|
+
|
|
149
|
+
easy.http_patch("a=b")
|
|
150
|
+
assert_equal "PATCH\na=b", easy.body_str
|
|
151
|
+
|
|
152
|
+
easy.perform
|
|
153
|
+
assert_equal "GET", easy.body_str
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def test_put_request_does_not_leak_custom_method_to_next_perform
|
|
157
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
158
|
+
|
|
159
|
+
easy.http_put("payload")
|
|
160
|
+
assert_equal "PUT\npayload", easy.body_str
|
|
161
|
+
|
|
162
|
+
easy.perform
|
|
163
|
+
assert_equal "GET", easy.body_str
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def test_failed_put_data_setup_does_not_leave_easy_in_upload_mode
|
|
167
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
168
|
+
easy.headers = ["X-Test: true"]
|
|
169
|
+
|
|
170
|
+
assert_raise(RuntimeError) { easy.put_data = "payload" }
|
|
171
|
+
|
|
172
|
+
easy.headers = {}
|
|
173
|
+
easy.perform
|
|
174
|
+
assert_equal "GET", easy.body_str
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def test_perform_releases_failed_implicit_multi_without_follow_up_easy_perform
|
|
178
|
+
Curl::Easy.flush_deferred_multi_closes
|
|
179
|
+
assert_equal 0, Curl::Easy.deferred_multi_closes.length
|
|
180
|
+
|
|
181
|
+
easy, implicit_multi = capture_failed_implicit_multi_cleanup_state
|
|
182
|
+
|
|
183
|
+
assert_nil easy.multi
|
|
184
|
+
assert_equal({}, implicit_multi.requests)
|
|
185
|
+
assert_equal false, implicit_multi.instance_variable_get(:@deferred_close)
|
|
186
|
+
assert_equal 0, Curl::Easy.deferred_multi_closes.length
|
|
187
|
+
ensure
|
|
188
|
+
easy.multi = nil if defined?(easy) && easy
|
|
189
|
+
implicit_multi.close if defined?(implicit_multi) && implicit_multi
|
|
190
|
+
Curl::Easy.flush_deferred_multi_closes
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def test_deferred_multi_closes_stay_with_their_owner_thread_across_retry
|
|
194
|
+
Curl::Easy.flush_deferred_multi_closes(all_threads: true)
|
|
195
|
+
multi = deferred_close_stub_multi(failures: 1)
|
|
196
|
+
|
|
197
|
+
Curl::Easy.defer_multi_close(multi, nil)
|
|
198
|
+
|
|
199
|
+
Curl::Easy.flush_deferred_multi_closes
|
|
200
|
+
assert_equal 1, multi.close_attempts
|
|
201
|
+
assert_equal true, multi.instance_variable_get(:@deferred_close)
|
|
202
|
+
assert_equal 1, Curl::Easy.deferred_multi_closes.length
|
|
203
|
+
|
|
204
|
+
Thread.new { Curl::Easy.flush_deferred_multi_closes }.join
|
|
205
|
+
assert_equal 1, multi.close_attempts
|
|
206
|
+
assert_equal true, multi.instance_variable_get(:@deferred_close)
|
|
207
|
+
assert_equal 1, Curl::Easy.deferred_multi_closes.length
|
|
208
|
+
|
|
209
|
+
Curl::Easy.flush_deferred_multi_closes
|
|
210
|
+
assert_equal 2, multi.close_attempts
|
|
211
|
+
assert_equal true, multi.closed?
|
|
212
|
+
assert_equal false, multi.instance_variable_get(:@deferred_close)
|
|
213
|
+
assert_equal 0, Curl::Easy.deferred_multi_closes.length
|
|
214
|
+
ensure
|
|
215
|
+
Curl::Easy.flush_deferred_multi_closes(all_threads: true)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def capture_created_multis
|
|
219
|
+
created_multis = []
|
|
220
|
+
multi_singleton = class << Curl::Multi; self; end
|
|
221
|
+
|
|
222
|
+
multi_singleton.__send__(:alias_method, :__curb_test_original_new, :new)
|
|
223
|
+
multi_singleton.__send__(:define_method, :new) do |*args, &block|
|
|
224
|
+
multi = __curb_test_original_new(*args, &block)
|
|
225
|
+
created_multis << multi
|
|
226
|
+
multi
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
yield created_multis
|
|
230
|
+
ensure
|
|
231
|
+
if defined?(multi_singleton) && multi_singleton.method_defined?(:__curb_test_original_new)
|
|
232
|
+
multi_singleton.__send__(:remove_method, :new)
|
|
233
|
+
multi_singleton.__send__(:alias_method, :new, :__curb_test_original_new)
|
|
234
|
+
multi_singleton.__send__(:remove_method, :__curb_test_original_new)
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def capture_failed_implicit_multi_cleanup_state
|
|
239
|
+
created_multis = nil
|
|
240
|
+
easy = nil
|
|
241
|
+
|
|
242
|
+
capture_created_multis do |captured_multis|
|
|
243
|
+
created_multis = captured_multis
|
|
244
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
245
|
+
easy.on_complete { raise "complete blew up" }
|
|
246
|
+
|
|
247
|
+
error = assert_raise(Curl::Err::AbortedByCallbackError) { easy.perform }
|
|
248
|
+
assert_equal "complete blew up", error.message
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
assert_equal 1, created_multis.length, "test should observe one implicit multi created by Easy#perform"
|
|
252
|
+
|
|
253
|
+
[easy, created_multis.first]
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def deferred_close_stub_multi(failures:)
|
|
257
|
+
Object.new.tap do |multi|
|
|
258
|
+
requests = {}
|
|
259
|
+
remaining_failures = failures
|
|
260
|
+
close_attempts = 0
|
|
261
|
+
closed = false
|
|
262
|
+
|
|
263
|
+
multi.define_singleton_method(:requests) { requests }
|
|
264
|
+
multi.define_singleton_method(:_close) do
|
|
265
|
+
close_attempts += 1
|
|
266
|
+
if remaining_failures.positive?
|
|
267
|
+
remaining_failures -= 1
|
|
268
|
+
raise "close failed"
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
closed = true
|
|
272
|
+
end
|
|
273
|
+
multi.define_singleton_method(:close_attempts) { close_attempts }
|
|
274
|
+
multi.define_singleton_method(:closed?) { closed }
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def test_perform_restores_explicit_multi_after_callback_error
|
|
279
|
+
multi = Curl::Multi.new
|
|
280
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
281
|
+
easy.multi = multi
|
|
282
|
+
easy.on_complete { raise "complete blew up" }
|
|
283
|
+
|
|
284
|
+
error = assert_raise(Curl::Err::AbortedByCallbackError) { easy.perform }
|
|
285
|
+
assert_equal "complete blew up", error.message
|
|
286
|
+
assert_same multi, easy.multi
|
|
287
|
+
assert_equal({}, multi.requests)
|
|
288
|
+
|
|
289
|
+
easy.on_complete { |_curl| }
|
|
290
|
+
easy.perform
|
|
291
|
+
|
|
292
|
+
assert_same multi, easy.multi
|
|
293
|
+
assert_equal "GET", easy.body_str
|
|
294
|
+
ensure
|
|
295
|
+
easy.multi = nil if defined?(easy) && easy && easy.multi.equal?(multi)
|
|
296
|
+
multi.close if defined?(multi) && multi
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def test_perform_restores_cached_implicit_multi_after_callback_error
|
|
300
|
+
Curl::Multi.autoclose = false
|
|
301
|
+
|
|
302
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
303
|
+
easy.perform
|
|
304
|
+
|
|
305
|
+
cached_multi = easy.multi
|
|
306
|
+
easy.on_complete { raise "complete blew up" }
|
|
307
|
+
|
|
308
|
+
error = assert_raise(Curl::Err::AbortedByCallbackError) { easy.perform }
|
|
309
|
+
assert_equal "complete blew up", error.message
|
|
310
|
+
assert_same cached_multi, easy.multi
|
|
311
|
+
assert_equal({}, cached_multi.requests)
|
|
312
|
+
|
|
313
|
+
easy.on_complete { |_curl| }
|
|
314
|
+
easy.perform
|
|
315
|
+
|
|
316
|
+
assert_same cached_multi, easy.multi
|
|
317
|
+
assert_equal "GET", easy.body_str
|
|
318
|
+
ensure
|
|
319
|
+
easy.multi = nil if defined?(easy) && easy
|
|
320
|
+
cached_multi.close if defined?(cached_multi) && cached_multi
|
|
321
|
+
Curl::Multi.autoclose = false
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def test_close_clears_explicit_idle_easy_multi_reference
|
|
325
|
+
easy = Curl::Easy.new($TEST_URL)
|
|
326
|
+
multi = Curl::Multi.new
|
|
327
|
+
easy.multi = multi
|
|
328
|
+
|
|
329
|
+
assert_same multi, easy.multi
|
|
330
|
+
assert_equal({}, multi.requests)
|
|
331
|
+
|
|
332
|
+
multi.close
|
|
333
|
+
|
|
334
|
+
assert_nil easy.multi
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def test_close_clears_cached_idle_easy_multi_reference
|
|
338
|
+
Curl::Multi.autoclose = false
|
|
339
|
+
|
|
340
|
+
easy = Curl::Easy.new($TEST_URL)
|
|
341
|
+
easy.perform
|
|
342
|
+
|
|
343
|
+
cached_multi = easy.multi
|
|
344
|
+
assert_not_nil cached_multi
|
|
345
|
+
assert_equal({}, cached_multi.requests)
|
|
346
|
+
|
|
347
|
+
cached_multi.close
|
|
348
|
+
|
|
349
|
+
assert_nil easy.multi
|
|
350
|
+
ensure
|
|
351
|
+
easy.multi = nil if defined?(easy) && easy
|
|
352
|
+
Curl::Multi.autoclose = false
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def test_multi_assignment_rejects_non_multi_objects
|
|
356
|
+
easy = Curl::Easy.new($TEST_URL)
|
|
357
|
+
|
|
358
|
+
error = assert_raise(TypeError) { easy.multi = Object.new }
|
|
359
|
+
|
|
360
|
+
assert_match(/Curl::Multi/, error.message)
|
|
361
|
+
assert_nil easy.multi
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def test_perform_can_reuse_explicit_multi_when_autoclose_is_enabled
|
|
365
|
+
Curl::Multi.autoclose = true
|
|
366
|
+
|
|
367
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
368
|
+
multi = Curl::Multi.new
|
|
369
|
+
|
|
370
|
+
easy.multi = multi
|
|
371
|
+
easy.perform
|
|
372
|
+
|
|
373
|
+
assert_nil easy.multi
|
|
374
|
+
assert_equal({}, multi.requests)
|
|
375
|
+
|
|
376
|
+
easy.multi = multi
|
|
377
|
+
easy.perform
|
|
378
|
+
|
|
379
|
+
assert_nil easy.multi
|
|
380
|
+
assert_equal({}, multi.requests)
|
|
381
|
+
assert_equal "GET", easy.body_str
|
|
382
|
+
ensure
|
|
383
|
+
easy.multi = nil if defined?(easy) && easy
|
|
384
|
+
multi.close if defined?(multi) && multi
|
|
385
|
+
Curl::Multi.autoclose = false
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def test_perform_reraises_on_body_exception_for_frozen_easy
|
|
389
|
+
easy = Curl::Easy.new($TEST_URL)
|
|
390
|
+
callback_error = Class.new(RuntimeError)
|
|
391
|
+
easy.on_body { raise callback_error, "body blew up" }
|
|
392
|
+
easy.freeze
|
|
393
|
+
|
|
394
|
+
error = assert_raise(callback_error) { easy.perform }
|
|
395
|
+
|
|
396
|
+
assert_equal "body blew up", error.message
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def test_perform_preserves_implicit_multi_when_autoclose_is_disabled
|
|
400
|
+
Curl::Multi.autoclose = false
|
|
401
|
+
|
|
402
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
403
|
+
easy.perform
|
|
404
|
+
|
|
405
|
+
first_multi = easy.multi
|
|
406
|
+
assert_not_nil first_multi
|
|
407
|
+
assert_equal({}, first_multi.requests)
|
|
408
|
+
|
|
409
|
+
easy.perform
|
|
410
|
+
|
|
411
|
+
assert_same first_multi, easy.multi
|
|
412
|
+
assert_equal "GET", easy.body_str
|
|
413
|
+
ensure
|
|
414
|
+
easy.multi = nil if defined?(easy) && easy
|
|
415
|
+
first_multi.close if defined?(first_multi) && first_multi
|
|
416
|
+
Curl::Multi.autoclose = false
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def test_curlopt_stderr_fails_with_tempdir
|
|
420
|
+
Tempfile.open('curb_test_curlopt_stderr') do |tempfile|
|
|
421
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
422
|
+
|
|
423
|
+
assert_raise(TypeError) do
|
|
424
|
+
easy.setopt(Curl::CURLOPT_STDERR, tempfile)
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
def test_curlopt_stderr_fails_with_stringio
|
|
430
|
+
stringio = StringIO.new
|
|
431
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
432
|
+
|
|
433
|
+
assert_raise(TypeError) do
|
|
434
|
+
easy.setopt(Curl::CURLOPT_STDERR, stringio)
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
def test_curlopt_stderr_fails_with_string
|
|
439
|
+
string = String.new
|
|
440
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
441
|
+
|
|
442
|
+
assert_raise(TypeError) do
|
|
443
|
+
easy.setopt(Curl::CURLOPT_STDERR, string)
|
|
444
|
+
end
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
def test_exception
|
|
448
|
+
begin
|
|
449
|
+
Curl.get('NOT_FOUND_URL')
|
|
450
|
+
rescue
|
|
451
|
+
assert true
|
|
452
|
+
rescue Exception
|
|
453
|
+
assert false, "We should raise StandardError"
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
|
|
7
457
|
def test_threads
|
|
8
458
|
t = []
|
|
9
459
|
5.times do
|
|
@@ -12,33 +462,29 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
12
462
|
c = Curl.get($TEST_URL)
|
|
13
463
|
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
|
|
14
464
|
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body)
|
|
15
|
-
assert_equal "", c.header_str
|
|
16
|
-
assert_equal "", c.head
|
|
17
465
|
end
|
|
18
466
|
end
|
|
19
467
|
end
|
|
20
468
|
|
|
21
|
-
t.each {|
|
|
469
|
+
t.each {|x| x.join }
|
|
22
470
|
end
|
|
23
471
|
|
|
24
472
|
def test_class_perform_01
|
|
25
473
|
assert_instance_of Curl::Easy, c = Curl::Easy.perform($TEST_URL)
|
|
26
474
|
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
|
|
27
475
|
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body)
|
|
28
|
-
assert_equal "", c.header_str
|
|
29
476
|
end
|
|
30
477
|
|
|
31
478
|
def test_class_perform_02
|
|
32
|
-
data =
|
|
479
|
+
data = String.new
|
|
33
480
|
assert_instance_of Curl::Easy, c = Curl::Easy.perform($TEST_URL) { |curl| curl.on_body { |d| data << d; d.length } }
|
|
34
481
|
|
|
35
482
|
assert_nil c.body_str
|
|
36
|
-
assert_equal "", c.header_str
|
|
37
483
|
assert_match(/^# DO NOT REMOVE THIS COMMENT/, data)
|
|
38
484
|
end
|
|
39
485
|
|
|
40
486
|
def test_class_perform_03
|
|
41
|
-
assert_raise(Curl::Err::CouldntReadError) {
|
|
487
|
+
assert_raise(Curl::Err::CouldntReadError) { Curl::Easy.perform($TEST_URL + "nonexistent") }
|
|
42
488
|
end
|
|
43
489
|
|
|
44
490
|
def test_new_01
|
|
@@ -128,11 +574,10 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
128
574
|
c = Curl::Easy.new($TEST_URL)
|
|
129
575
|
assert_equal true, c.http_get
|
|
130
576
|
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
|
|
131
|
-
assert_equal "", c.header_str
|
|
132
577
|
end
|
|
133
578
|
|
|
134
579
|
def test_get_02
|
|
135
|
-
data =
|
|
580
|
+
data = String.new
|
|
136
581
|
c = Curl::Easy.new($TEST_URL) do |curl|
|
|
137
582
|
curl.on_body { |d| data << d; d.length }
|
|
138
583
|
end
|
|
@@ -140,7 +585,6 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
140
585
|
assert_equal true, c.http_get
|
|
141
586
|
|
|
142
587
|
assert_nil c.body_str
|
|
143
|
-
assert_equal "", c.header_str
|
|
144
588
|
assert_match(/^# DO NOT REMOVE THIS COMMENT/, data)
|
|
145
589
|
end
|
|
146
590
|
|
|
@@ -153,6 +597,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
153
597
|
|
|
154
598
|
|
|
155
599
|
def test_last_effective_url_01
|
|
600
|
+
omit('Windows file URL semantics differ') if WINDOWS
|
|
156
601
|
c = Curl::Easy.new($TEST_URL)
|
|
157
602
|
|
|
158
603
|
assert_equal $TEST_URL, c.url
|
|
@@ -323,19 +768,71 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
323
768
|
c.max_redirects = nil
|
|
324
769
|
assert_nil c.max_redirects
|
|
325
770
|
end
|
|
326
|
-
|
|
771
|
+
|
|
772
|
+
def test_timeout_with_floats
|
|
773
|
+
c = Curl::Easy.new($TEST_URL)
|
|
774
|
+
|
|
775
|
+
c.timeout = 1.5
|
|
776
|
+
assert_equal 1500, c.timeout_ms
|
|
777
|
+
assert_equal 1.5, c.timeout
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
def test_timeout_with_negative
|
|
781
|
+
c = Curl::Easy.new($TEST_URL)
|
|
782
|
+
|
|
783
|
+
c.timeout = -1.5
|
|
784
|
+
assert_equal 0, c.timeout
|
|
785
|
+
assert_equal 0, c.timeout_ms
|
|
786
|
+
|
|
787
|
+
c.timeout = -4.8
|
|
788
|
+
assert_equal 0, c.timeout
|
|
789
|
+
assert_equal 0, c.timeout_ms
|
|
790
|
+
end
|
|
791
|
+
|
|
327
792
|
def test_timeout_01
|
|
328
793
|
c = Curl::Easy.new($TEST_URL)
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
794
|
+
|
|
795
|
+
assert_equal 0, c.timeout
|
|
796
|
+
|
|
332
797
|
c.timeout = 3
|
|
333
798
|
assert_equal 3, c.timeout
|
|
334
|
-
|
|
335
|
-
c.timeout =
|
|
336
|
-
|
|
799
|
+
|
|
800
|
+
c.timeout = 0
|
|
801
|
+
assert_equal 0, c.timeout
|
|
337
802
|
end
|
|
338
|
-
|
|
803
|
+
|
|
804
|
+
def test_timeout_ms_01
|
|
805
|
+
c = Curl::Easy.new($TEST_URL)
|
|
806
|
+
|
|
807
|
+
assert_equal 0, c.timeout_ms
|
|
808
|
+
|
|
809
|
+
c.timeout_ms = 100
|
|
810
|
+
assert_equal 100, c.timeout_ms
|
|
811
|
+
|
|
812
|
+
c.timeout_ms = nil
|
|
813
|
+
assert_equal 0, c.timeout_ms
|
|
814
|
+
end
|
|
815
|
+
|
|
816
|
+
def test_timeout_ms_with_floats
|
|
817
|
+
c = Curl::Easy.new($TEST_URL)
|
|
818
|
+
|
|
819
|
+
c.timeout_ms = 55.5
|
|
820
|
+
assert_equal 55, c.timeout_ms
|
|
821
|
+
assert_equal 0.055, c.timeout
|
|
822
|
+
end
|
|
823
|
+
|
|
824
|
+
def test_timeout_ms_with_negative
|
|
825
|
+
c = Curl::Easy.new($TEST_URL)
|
|
826
|
+
|
|
827
|
+
c.timeout_ms = -1.5
|
|
828
|
+
assert_equal 0, c.timeout
|
|
829
|
+
assert_equal 0, c.timeout_ms
|
|
830
|
+
|
|
831
|
+
c.timeout_ms = -4.8
|
|
832
|
+
assert_equal 0, c.timeout
|
|
833
|
+
assert_equal 0, c.timeout_ms
|
|
834
|
+
end
|
|
835
|
+
|
|
339
836
|
def test_connect_timeout_01
|
|
340
837
|
c = Curl::Easy.new($TEST_URL)
|
|
341
838
|
|
|
@@ -347,7 +844,19 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
347
844
|
c.connect_timeout = nil
|
|
348
845
|
assert_nil c.connect_timeout
|
|
349
846
|
end
|
|
350
|
-
|
|
847
|
+
|
|
848
|
+
def test_connect_timeout_ms_01
|
|
849
|
+
c = Curl::Easy.new($TEST_URL)
|
|
850
|
+
|
|
851
|
+
assert_nil c.connect_timeout_ms
|
|
852
|
+
|
|
853
|
+
c.connect_timeout_ms = 100
|
|
854
|
+
assert_equal 100, c.connect_timeout_ms
|
|
855
|
+
|
|
856
|
+
c.connect_timeout_ms = nil
|
|
857
|
+
assert_nil c.connect_timeout_ms
|
|
858
|
+
end
|
|
859
|
+
|
|
351
860
|
def test_ftp_response_timeout_01
|
|
352
861
|
c = Curl::Easy.new($TEST_URL)
|
|
353
862
|
|
|
@@ -537,6 +1046,27 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
537
1046
|
assert_raises(ArgumentError) { c.resolve_mode = :bad }
|
|
538
1047
|
end
|
|
539
1048
|
|
|
1049
|
+
def test_http_version_accessors
|
|
1050
|
+
c = Curl::Easy.new
|
|
1051
|
+
assert_equal Curl::HTTP_NONE, c.http_version
|
|
1052
|
+
|
|
1053
|
+
c.http_version = Curl::HTTP_1_1
|
|
1054
|
+
assert_equal Curl::HTTP_1_1, c.http_version
|
|
1055
|
+
|
|
1056
|
+
if Curl.const_defined?(:HTTP_2TLS)
|
|
1057
|
+
c.http_version = Curl::HTTP_2TLS
|
|
1058
|
+
assert_equal Curl::HTTP_2TLS, c.http_version
|
|
1059
|
+
end
|
|
1060
|
+
|
|
1061
|
+
if Curl.const_defined?(:HTTP_2_PRIOR_KNOWLEDGE)
|
|
1062
|
+
c.http_version = Curl::HTTP_2_PRIOR_KNOWLEDGE
|
|
1063
|
+
assert_equal Curl::HTTP_2_PRIOR_KNOWLEDGE, c.http_version
|
|
1064
|
+
end
|
|
1065
|
+
|
|
1066
|
+
c.http_version = nil
|
|
1067
|
+
assert_equal Curl::HTTP_NONE, c.http_version
|
|
1068
|
+
end
|
|
1069
|
+
|
|
540
1070
|
def test_enable_cookies
|
|
541
1071
|
c = Curl::Easy.new
|
|
542
1072
|
assert !c.enable_cookies?
|
|
@@ -565,14 +1095,23 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
565
1095
|
assert_equal "some.file", c.cookiejar
|
|
566
1096
|
end
|
|
567
1097
|
|
|
1098
|
+
def test_cookielist
|
|
1099
|
+
c = Curl::Easy.new TestServlet.url
|
|
1100
|
+
c.enable_cookies = true
|
|
1101
|
+
c.post_body = URI.encode_www_form('c' => 'somename=somevalue')
|
|
1102
|
+
assert_nil c.cookielist
|
|
1103
|
+
c.perform
|
|
1104
|
+
assert_match(/somevalue/, c.cookielist.join(''))
|
|
1105
|
+
end
|
|
1106
|
+
|
|
568
1107
|
def test_on_success
|
|
569
1108
|
curl = Curl::Easy.new($TEST_URL)
|
|
570
1109
|
on_success_called = false
|
|
571
1110
|
curl.on_success {|c|
|
|
572
1111
|
on_success_called = true
|
|
573
|
-
assert_not_nil c.
|
|
574
|
-
|
|
575
|
-
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.
|
|
1112
|
+
assert_not_nil c.body
|
|
1113
|
+
assert_match(/Content-Length: /, c.head)
|
|
1114
|
+
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body)
|
|
576
1115
|
}
|
|
577
1116
|
curl.perform
|
|
578
1117
|
assert on_success_called, "Success handler not called"
|
|
@@ -614,20 +1153,27 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
614
1153
|
assert_equal 'GET', curl.body_str
|
|
615
1154
|
end
|
|
616
1155
|
|
|
617
|
-
def
|
|
1156
|
+
def test_remote
|
|
618
1157
|
curl = Curl::Easy.new(TestServlet.url)
|
|
619
1158
|
curl.http_post([Curl::PostField.content('document_id', 5)])
|
|
620
1159
|
assert_equal "POST\ndocument_id=5", curl.unescape(curl.body_str)
|
|
1160
|
+
|
|
1161
|
+
curl.http_put([Curl::PostField.content('document_id', 5)])
|
|
1162
|
+
assert_equal "PUT\ndocument_id=5", curl.unescape(curl.body_str)
|
|
1163
|
+
|
|
1164
|
+
curl.http_patch([Curl::PostField.content('document_id', 5)])
|
|
1165
|
+
assert_equal "PATCH\ndocument_id=5", curl.unescape(curl.body_str)
|
|
621
1166
|
end
|
|
622
1167
|
|
|
623
|
-
def
|
|
1168
|
+
def test_remote_is_easy_handle
|
|
624
1169
|
# see: http://pastie.org/560852 and
|
|
625
1170
|
# http://groups.google.com/group/curb---ruby-libcurl-bindings/browse_thread/thread/216bb2d9b037f347?hl=en
|
|
626
|
-
[:post, :get, :head, :delete].each do |method|
|
|
1171
|
+
[:post, :patch, :put, :get, :head, :delete].each do |method|
|
|
627
1172
|
retries = 0
|
|
628
1173
|
begin
|
|
629
1174
|
count = 0
|
|
630
|
-
|
|
1175
|
+
m = "http_#{method}".to_sym
|
|
1176
|
+
Curl::Easy.send(m, TestServlet.url) do|c|
|
|
631
1177
|
count += 1
|
|
632
1178
|
assert_equal Curl::Easy, c.class
|
|
633
1179
|
end
|
|
@@ -636,24 +1182,40 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
636
1182
|
retries+=1
|
|
637
1183
|
retry if retries < 3
|
|
638
1184
|
raise e
|
|
1185
|
+
rescue ArgumentError => e
|
|
1186
|
+
assert false, "#{m} - #{e.message}"
|
|
639
1187
|
end
|
|
640
1188
|
end
|
|
641
1189
|
end
|
|
642
1190
|
|
|
643
1191
|
# see: https://github.com/rvanlieshout/curb/commit/8bcdefddc0162484681ebd1a92d52a642666a445
|
|
644
|
-
def
|
|
1192
|
+
def test_multipart_array_remote
|
|
645
1193
|
curl = Curl::Easy.new(TestServlet.url)
|
|
646
1194
|
curl.multipart_form_post = true
|
|
647
1195
|
fields = [
|
|
648
|
-
Curl::PostField.file('foo', File.expand_path(File.join(File.dirname(__FILE__),'..','README'))),
|
|
649
|
-
Curl::PostField.file('bar', File.expand_path(File.join(File.dirname(__FILE__),'..','README')))
|
|
1196
|
+
Curl::PostField.file('foo', File.expand_path(File.join(File.dirname(__FILE__),'..','README.md'))),
|
|
1197
|
+
Curl::PostField.file('bar', File.expand_path(File.join(File.dirname(__FILE__),'..','README.md')))
|
|
650
1198
|
]
|
|
651
1199
|
curl.http_post(fields)
|
|
652
|
-
assert_match
|
|
653
|
-
assert_match
|
|
1200
|
+
assert_match(/HTTP POST file upload/, curl.body_str)
|
|
1201
|
+
assert_match(/Content-Disposition: form-data/, curl.body_str)
|
|
1202
|
+
|
|
1203
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1204
|
+
curl.multipart_form_post = true
|
|
1205
|
+
fields = [
|
|
1206
|
+
Curl::PostField.file('foo', File.expand_path(File.join(File.dirname(__FILE__),'..','README.md'))),
|
|
1207
|
+
Curl::PostField.file('bar', File.expand_path(File.join(File.dirname(__FILE__),'..','README.md')))
|
|
1208
|
+
]
|
|
1209
|
+
curl.http_put(fields)
|
|
1210
|
+
assert_match(/HTTP POST file upload/, curl.body_str)
|
|
1211
|
+
assert_match(/Content-Disposition: form-data/, curl.body_str)
|
|
1212
|
+
|
|
1213
|
+
curl.http_patch(fields)
|
|
1214
|
+
assert_match(/HTTP POST file upload/, curl.body_str)
|
|
1215
|
+
assert_match(/Content-Disposition: form-data/, curl.body_str)
|
|
654
1216
|
end
|
|
655
1217
|
|
|
656
|
-
def
|
|
1218
|
+
def test_with_body_remote
|
|
657
1219
|
curl = Curl::Easy.new(TestServlet.url)
|
|
658
1220
|
curl.post_body = 'foo=bar&encoded%20string=val'
|
|
659
1221
|
|
|
@@ -661,23 +1223,151 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
661
1223
|
|
|
662
1224
|
assert_equal "POST\nfoo=bar&encoded%20string=val", curl.body_str
|
|
663
1225
|
assert_equal 'foo=bar&encoded%20string=val', curl.post_body
|
|
1226
|
+
|
|
1227
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1228
|
+
curl.put_data = 'foo=bar&encoded%20string=val'
|
|
1229
|
+
|
|
1230
|
+
curl.perform
|
|
1231
|
+
|
|
1232
|
+
assert_equal "PUT\nfoo=bar&encoded%20string=val", curl.body_str
|
|
664
1233
|
end
|
|
665
|
-
|
|
666
|
-
def
|
|
1234
|
+
|
|
1235
|
+
def test_post_body_from_to_s_keeps_string_buffer_alive
|
|
1236
|
+
post_body = Object.new
|
|
1237
|
+
def post_body.to_s
|
|
1238
|
+
'foo=bar&encoded%20string=val'
|
|
1239
|
+
end
|
|
1240
|
+
|
|
1241
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1242
|
+
curl.post_body = post_body
|
|
1243
|
+
|
|
1244
|
+
assert_equal 'foo=bar&encoded%20string=val', curl.post_body
|
|
1245
|
+
|
|
1246
|
+
GC.start
|
|
1247
|
+
GC.compact if GC.respond_to?(:compact)
|
|
1248
|
+
|
|
1249
|
+
curl.perform
|
|
1250
|
+
assert_equal "POST\nfoo=bar&encoded%20string=val", curl.body_str
|
|
1251
|
+
end
|
|
1252
|
+
|
|
1253
|
+
def test_post_body_preserves_assigned_snapshot_when_original_string_is_mutated
|
|
1254
|
+
omit('CURLOPT_COPYPOSTFIELDS is not available in this build') unless Curl.const_defined?(:CURLOPT_COPYPOSTFIELDS)
|
|
1255
|
+
|
|
1256
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1257
|
+
post_body = String.new('alpha=1')
|
|
1258
|
+
curl.post_body = post_body
|
|
1259
|
+
|
|
1260
|
+
post_body.replace('beta=2')
|
|
1261
|
+
|
|
1262
|
+
assert_equal 'beta=2', post_body
|
|
1263
|
+
assert_equal 'alpha=1', curl.post_body
|
|
1264
|
+
|
|
1265
|
+
curl.perform
|
|
1266
|
+
|
|
1267
|
+
assert_equal "POST\nalpha=1", curl.body_str
|
|
1268
|
+
assert_equal 'alpha=1', curl.post_body
|
|
1269
|
+
end
|
|
1270
|
+
|
|
1271
|
+
def test_setopt_postfields_keeps_string_buffer_alive
|
|
1272
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1273
|
+
curl.set(Curl::CURLOPT_POSTFIELDS, 'foo=bar&encoded%20string=val')
|
|
1274
|
+
|
|
1275
|
+
assert_equal 'foo=bar&encoded%20string=val', curl.post_body
|
|
1276
|
+
|
|
1277
|
+
GC.start
|
|
1278
|
+
GC.compact if GC.respond_to?(:compact)
|
|
1279
|
+
|
|
1280
|
+
curl.perform
|
|
1281
|
+
assert_equal "POST\nfoo=bar&encoded%20string=val", curl.body_str
|
|
1282
|
+
end
|
|
1283
|
+
|
|
1284
|
+
def test_setopt_postfields_preserves_assigned_snapshot_when_original_string_is_mutated
|
|
1285
|
+
omit('CURLOPT_COPYPOSTFIELDS is not available in this build') unless Curl.const_defined?(:CURLOPT_COPYPOSTFIELDS)
|
|
1286
|
+
|
|
1287
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1288
|
+
post_body = String.new('alpha=1')
|
|
1289
|
+
curl.set(Curl::CURLOPT_POSTFIELDS, post_body)
|
|
1290
|
+
|
|
1291
|
+
post_body.replace('beta=2')
|
|
1292
|
+
|
|
1293
|
+
assert_equal 'beta=2', post_body
|
|
1294
|
+
assert_equal 'alpha=1', curl.post_body
|
|
1295
|
+
|
|
1296
|
+
curl.perform
|
|
1297
|
+
|
|
1298
|
+
assert_equal "POST\nalpha=1", curl.body_str
|
|
1299
|
+
assert_equal 'alpha=1', curl.post_body
|
|
1300
|
+
end
|
|
1301
|
+
|
|
1302
|
+
def test_setopt_postfields_nil_preserves_post_request
|
|
1303
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1304
|
+
curl.set(Curl::CURLOPT_POST, true)
|
|
1305
|
+
curl.set(Curl::CURLOPT_POSTFIELDS, nil)
|
|
1306
|
+
|
|
1307
|
+
curl.perform
|
|
1308
|
+
|
|
1309
|
+
assert_nil curl.post_body
|
|
1310
|
+
assert_equal "POST\n", curl.body_str
|
|
1311
|
+
end
|
|
1312
|
+
|
|
1313
|
+
def test_form_body_remote
|
|
667
1314
|
curl = Curl::Easy.new(TestServlet.url)
|
|
668
1315
|
curl.http_post('foo=bar', 'encoded%20string=val')
|
|
669
1316
|
|
|
670
1317
|
assert_equal "POST\nfoo=bar&encoded%20string=val", curl.body_str
|
|
671
1318
|
assert_equal 'foo=bar&encoded%20string=val', curl.post_body
|
|
1319
|
+
|
|
1320
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1321
|
+
curl.http_put('foo=bar', 'encoded%20string=val')
|
|
1322
|
+
|
|
1323
|
+
assert_equal "PUT\nfoo=bar&encoded%20string=val", curl.body_str
|
|
1324
|
+
|
|
1325
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1326
|
+
curl.http_patch('foo=bar', 'encoded%20string=val')
|
|
1327
|
+
|
|
1328
|
+
assert_equal "PATCH\nfoo=bar&encoded%20string=val", curl.body_str
|
|
1329
|
+
end
|
|
1330
|
+
|
|
1331
|
+
def test_multipart_file_remote
|
|
1332
|
+
[:put, :post, :patch].each {|method|
|
|
1333
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1334
|
+
curl.multipart_form_post = true
|
|
1335
|
+
pf = Curl::PostField.file('readme', File.expand_path(File.join(File.dirname(__FILE__),'..','README.md')))
|
|
1336
|
+
curl.send("http_#{method}", pf)
|
|
1337
|
+
assert_match(/HTTP POST file upload/, curl.body_str)
|
|
1338
|
+
assert_match(/Content-Disposition: form-data/, curl.body_str)
|
|
1339
|
+
}
|
|
1340
|
+
end
|
|
1341
|
+
|
|
1342
|
+
def test_multipart_form_reuse_clears_previous_form
|
|
1343
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1344
|
+
curl.multipart_form_post = true
|
|
1345
|
+
curl.http_post(Curl::PostField.content('document_id', '5'))
|
|
1346
|
+
assert_match(/document_id/, curl.body_str)
|
|
1347
|
+
|
|
1348
|
+
curl.multipart_form_post = false
|
|
1349
|
+
curl.post_body = 'foo=bar'
|
|
1350
|
+
curl.http_post
|
|
1351
|
+
|
|
1352
|
+
assert_equal "POST\nfoo=bar", curl.body_str
|
|
672
1353
|
end
|
|
673
1354
|
|
|
674
|
-
def
|
|
1355
|
+
def test_multipart_patch_build_failure_restores_easy_request_state
|
|
675
1356
|
curl = Curl::Easy.new(TestServlet.url)
|
|
676
1357
|
curl.multipart_form_post = true
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
1358
|
+
field = Curl::PostField.content('document_id', '5')
|
|
1359
|
+
|
|
1360
|
+
field.name = nil
|
|
1361
|
+
error = assert_raise(Curl::Err::InvalidPostFieldError) do
|
|
1362
|
+
# The first field allocates native multipart form state before the second field raises.
|
|
1363
|
+
curl.http_patch(Curl::PostField.content('keep', 'allocated'), field)
|
|
1364
|
+
end
|
|
1365
|
+
assert_match(/Cannot post unnamed field/, error.message)
|
|
1366
|
+
|
|
1367
|
+
curl.multipart_form_post = false
|
|
1368
|
+
curl.perform
|
|
1369
|
+
|
|
1370
|
+
assert_equal 'GET', curl.body_str
|
|
681
1371
|
end
|
|
682
1372
|
|
|
683
1373
|
def test_delete_remote
|
|
@@ -699,7 +1389,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
699
1389
|
redirect = curl.header_str.match(/Location: (.*)/)
|
|
700
1390
|
|
|
701
1391
|
assert_equal '', curl.body_str
|
|
702
|
-
assert_match
|
|
1392
|
+
assert_match('/nonexistent', redirect[1])
|
|
703
1393
|
end
|
|
704
1394
|
|
|
705
1395
|
def test_head_accessor
|
|
@@ -710,7 +1400,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
710
1400
|
redirect = curl.header_str.match(/Location: (.*)/)
|
|
711
1401
|
|
|
712
1402
|
assert_equal '', curl.body_str
|
|
713
|
-
assert_match
|
|
1403
|
+
assert_match('/nonexistent', redirect[1])
|
|
714
1404
|
curl.head = false
|
|
715
1405
|
curl.perform
|
|
716
1406
|
assert_equal 'GET', curl.body_str
|
|
@@ -720,11 +1410,11 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
720
1410
|
curl = Curl::Easy.new(TestServlet.url)
|
|
721
1411
|
curl.headers['Content-Type'] = 'application/json'
|
|
722
1412
|
assert curl.http_put("message")
|
|
723
|
-
assert_match
|
|
724
|
-
assert_match
|
|
725
|
-
assert_match
|
|
726
|
-
assert_match
|
|
727
|
-
assert_match
|
|
1413
|
+
assert_match(/^PUT/, curl.body_str)
|
|
1414
|
+
assert_match(/message$/, curl.body_str)
|
|
1415
|
+
assert_match(/message$/, curl.body)
|
|
1416
|
+
assert_match(/application\/json/, curl.header_str)
|
|
1417
|
+
assert_match(/application\/json/, curl.head)
|
|
728
1418
|
end
|
|
729
1419
|
|
|
730
1420
|
def test_put_data
|
|
@@ -733,8 +1423,46 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
733
1423
|
|
|
734
1424
|
curl.perform
|
|
735
1425
|
|
|
736
|
-
assert_match
|
|
737
|
-
assert_match
|
|
1426
|
+
assert_match(/^PUT/, curl.body_str)
|
|
1427
|
+
assert_match(/message$/, curl.body_str)
|
|
1428
|
+
end
|
|
1429
|
+
|
|
1430
|
+
def test_put_data_from_to_s_object
|
|
1431
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1432
|
+
curl.put_data = :message
|
|
1433
|
+
|
|
1434
|
+
curl.perform
|
|
1435
|
+
|
|
1436
|
+
assert_equal "PUT\nmessage", curl.body_str
|
|
1437
|
+
end
|
|
1438
|
+
|
|
1439
|
+
def test_put_data_read_exception_sets_result_and_releases_callback_state
|
|
1440
|
+
error_class = Class.new(StandardError)
|
|
1441
|
+
reader_class = Class.new do
|
|
1442
|
+
define_method(:read) do |_len|
|
|
1443
|
+
raise error_class, 'upload read failed'
|
|
1444
|
+
end
|
|
1445
|
+
|
|
1446
|
+
def seek(_offset, _whence = SEEK_SET)
|
|
1447
|
+
0
|
|
1448
|
+
end
|
|
1449
|
+
|
|
1450
|
+
def stat
|
|
1451
|
+
Struct.new(:size).new(1)
|
|
1452
|
+
end
|
|
1453
|
+
end
|
|
1454
|
+
|
|
1455
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1456
|
+
curl.put_data = reader_class.new
|
|
1457
|
+
|
|
1458
|
+
error = assert_raise(error_class) { curl.perform }
|
|
1459
|
+
assert_equal 'upload read failed', error.message
|
|
1460
|
+
assert_not_equal 0, curl.last_result
|
|
1461
|
+
|
|
1462
|
+
curl.url = TestServlet.url
|
|
1463
|
+
curl.http_get
|
|
1464
|
+
|
|
1465
|
+
assert_equal 'GET', curl.body_str
|
|
738
1466
|
end
|
|
739
1467
|
|
|
740
1468
|
# https://github.com/taf2/curb/issues/101
|
|
@@ -744,8 +1472,8 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
744
1472
|
|
|
745
1473
|
curl.perform
|
|
746
1474
|
|
|
747
|
-
assert_match
|
|
748
|
-
assert_match
|
|
1475
|
+
assert_match(/^PUT/, curl.body_str)
|
|
1476
|
+
assert_match("a\0b", curl.body_str)
|
|
749
1477
|
end
|
|
750
1478
|
|
|
751
1479
|
def test_put_nil_data_no_crash
|
|
@@ -760,7 +1488,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
760
1488
|
File.open(__FILE__,'rb') do|f|
|
|
761
1489
|
assert curl.http_put(f)
|
|
762
1490
|
end
|
|
763
|
-
assert_equal "PUT\n#{File.read(__FILE__)}", curl.body_str
|
|
1491
|
+
assert_equal "PUT\n#{File.read(__FILE__)}", curl.body_str.tr("\r", '')
|
|
764
1492
|
end
|
|
765
1493
|
|
|
766
1494
|
def test_put_class_method
|
|
@@ -770,7 +1498,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
770
1498
|
assert_equal Curl::Easy, c.class
|
|
771
1499
|
end
|
|
772
1500
|
assert_equal 1, count
|
|
773
|
-
assert_equal "PUT\n#{File.read(__FILE__)}", curl.body_str
|
|
1501
|
+
assert_equal "PUT\n#{File.read(__FILE__)}", curl.body_str.tr("\r", '')
|
|
774
1502
|
end
|
|
775
1503
|
|
|
776
1504
|
# Generate a self-signed cert with
|
|
@@ -779,7 +1507,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
779
1507
|
def test_cert
|
|
780
1508
|
curl = Curl::Easy.new(TestServlet.url)
|
|
781
1509
|
curl.cert= File.join(File.dirname(__FILE__),"cert.pem")
|
|
782
|
-
assert_match
|
|
1510
|
+
assert_match(/cert.pem$/,curl.cert)
|
|
783
1511
|
end
|
|
784
1512
|
|
|
785
1513
|
def test_cert_with_password
|
|
@@ -787,7 +1515,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
787
1515
|
path = File.join(File.dirname(__FILE__),"cert.pem")
|
|
788
1516
|
curl.certpassword = 'password'
|
|
789
1517
|
curl.cert = path
|
|
790
|
-
assert_match
|
|
1518
|
+
assert_match(/cert.pem$/,curl.cert)
|
|
791
1519
|
end
|
|
792
1520
|
|
|
793
1521
|
def test_cert_type
|
|
@@ -808,7 +1536,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
808
1536
|
def test_ca_cert
|
|
809
1537
|
curl = Curl::Easy.new(TestServlet.url)
|
|
810
1538
|
curl.cacert= File.join(File.dirname(__FILE__),"cacert.pem")
|
|
811
|
-
assert_match
|
|
1539
|
+
assert_match(/cacert.pem$/, curl.cacert)
|
|
812
1540
|
end
|
|
813
1541
|
|
|
814
1542
|
def test_user_agent
|
|
@@ -834,7 +1562,15 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
834
1562
|
$auth_header = nil
|
|
835
1563
|
# curl checks the auth type supported by the server, so we have to create a
|
|
836
1564
|
# new easy handle if we're going to change the auth type...
|
|
837
|
-
|
|
1565
|
+
if WINDOWS
|
|
1566
|
+
# On Windows, libcurl often uses SSPI for NTLM which yields a different
|
|
1567
|
+
# header value and encoding; skip the NTLM-specific assertion.
|
|
1568
|
+
return
|
|
1569
|
+
end
|
|
1570
|
+
# curl 8.20.0 disables NTLM by default and plans to remove it in
|
|
1571
|
+
# September 2026; libcurl silently downgrades to Basic when NTLM is
|
|
1572
|
+
# unavailable, so skip the NTLM-specific assertion in that case.
|
|
1573
|
+
return unless Curl.ntlm?
|
|
838
1574
|
curl = Curl::Easy.new(TestServlet.url)
|
|
839
1575
|
curl.username = "foo"
|
|
840
1576
|
curl.password = "bar"
|
|
@@ -855,7 +1591,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
855
1591
|
end
|
|
856
1592
|
|
|
857
1593
|
def test_post_streaming
|
|
858
|
-
readme = File.expand_path(File.join(File.dirname(__FILE__),'..','README'))
|
|
1594
|
+
readme = File.expand_path(File.join(File.dirname(__FILE__),'..','README.md'))
|
|
859
1595
|
|
|
860
1596
|
pf = Curl::PostField.file("filename", readme)
|
|
861
1597
|
|
|
@@ -865,11 +1601,10 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
865
1601
|
easy.multipart_form_post = true
|
|
866
1602
|
easy.http_post(pf)
|
|
867
1603
|
|
|
868
|
-
assert_not_equal(0,easy.
|
|
869
|
-
assert_equal(easy.
|
|
1604
|
+
assert_not_equal(0,easy.body.size)
|
|
1605
|
+
assert_equal(Digest::MD5.hexdigest(easy.body), Digest::MD5.hexdigest(File.binread(readme)))
|
|
870
1606
|
end
|
|
871
1607
|
|
|
872
|
-
|
|
873
1608
|
def test_easy_close
|
|
874
1609
|
easy = Curl::Easy.new
|
|
875
1610
|
easy.close
|
|
@@ -877,6 +1612,18 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
877
1612
|
easy.http_get
|
|
878
1613
|
end
|
|
879
1614
|
|
|
1615
|
+
def test_easy_close_restores_error_buffer
|
|
1616
|
+
easy = Curl::Easy.new('http://127.0.0.1:1')
|
|
1617
|
+
assert_raise(Curl::Err::ConnectionFailedError) { easy.perform }
|
|
1618
|
+
assert_not_nil easy.last_error
|
|
1619
|
+
|
|
1620
|
+
easy.close
|
|
1621
|
+
easy.url = 'http://127.0.0.1:1'
|
|
1622
|
+
assert_raise(Curl::Err::ConnectionFailedError) { easy.perform }
|
|
1623
|
+
|
|
1624
|
+
assert_not_nil easy.last_error
|
|
1625
|
+
end
|
|
1626
|
+
|
|
880
1627
|
def test_easy_reset
|
|
881
1628
|
easy = Curl::Easy.new
|
|
882
1629
|
easy.url = TestServlet.url + "?query=foo"
|
|
@@ -889,6 +1636,48 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
889
1636
|
easy.http_get
|
|
890
1637
|
end
|
|
891
1638
|
|
|
1639
|
+
def test_easy_reset_clears_network_policy_allowlists
|
|
1640
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
1641
|
+
easy.allowed_hosts = ['127.0.0.1']
|
|
1642
|
+
easy.network_policy = :public
|
|
1643
|
+
easy.allowed_cidrs = ['1.1.1.0/24']
|
|
1644
|
+
|
|
1645
|
+
settings = easy.reset
|
|
1646
|
+
|
|
1647
|
+
assert settings.key?(:allowed_hosts)
|
|
1648
|
+
assert settings.key?(:allowed_cidrs)
|
|
1649
|
+
assert_nil easy.allowed_hosts
|
|
1650
|
+
assert_nil easy.allowed_cidrs
|
|
1651
|
+
assert_equal :none, easy.network_policy
|
|
1652
|
+
rescue NotImplementedError
|
|
1653
|
+
omit('network_policy=:public requires CURLOPT_OPENSOCKETFUNCTION support')
|
|
1654
|
+
end
|
|
1655
|
+
|
|
1656
|
+
def test_frozen_easy_close_and_reset_skip_safety_override_cleanup
|
|
1657
|
+
closed_easy = Curl::Easy.new
|
|
1658
|
+
closed_easy.freeze
|
|
1659
|
+
|
|
1660
|
+
assert_nothing_raised { closed_easy.close }
|
|
1661
|
+
|
|
1662
|
+
reset_easy = Curl::Easy.new
|
|
1663
|
+
reset_easy.safe_http!
|
|
1664
|
+
reset_easy.freeze
|
|
1665
|
+
|
|
1666
|
+
assert_nothing_raised { reset_easy.reset }
|
|
1667
|
+
end
|
|
1668
|
+
|
|
1669
|
+
def test_last_result_initialization
|
|
1670
|
+
# Test for issue #463 - ensure last_result is properly initialized to 0
|
|
1671
|
+
easy = Curl::Easy.new
|
|
1672
|
+
assert_equal 0, easy.last_result, "last_result should be initialized to 0 for new instance"
|
|
1673
|
+
|
|
1674
|
+
# Test that reset also sets last_result to 0
|
|
1675
|
+
easy.url = TestServlet.url
|
|
1676
|
+
easy.http_get
|
|
1677
|
+
easy.reset
|
|
1678
|
+
assert_equal 0, easy.last_result, "last_result should be reset to 0 after calling reset"
|
|
1679
|
+
end
|
|
1680
|
+
|
|
892
1681
|
def test_easy_use_http_versions
|
|
893
1682
|
easy = Curl::Easy.new
|
|
894
1683
|
easy.url = TestServlet.url + "?query=foo"
|
|
@@ -914,16 +1703,22 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
914
1703
|
assert_equal "PUT\nhello", curl.body_str
|
|
915
1704
|
curl.http('COPY')
|
|
916
1705
|
assert_equal 'COPY', curl.body_str
|
|
1706
|
+
|
|
1707
|
+
curl.http_patch
|
|
1708
|
+
assert_equal "PATCH\n", curl.body_str
|
|
1709
|
+
|
|
1710
|
+
curl.http_put
|
|
1711
|
+
assert_equal "PUT\n", curl.body_str
|
|
917
1712
|
end
|
|
918
1713
|
|
|
919
1714
|
def test_easy_http_verbs_must_respond_to_str
|
|
920
|
-
# issue http://github.com/taf2/curb/issues
|
|
1715
|
+
# issue http://github.com/taf2/curb/issues/45
|
|
921
1716
|
assert_nothing_raised do
|
|
922
|
-
c = Curl::Easy.new ; c.url =
|
|
1717
|
+
c = Curl::Easy.new ; c.url = TestServlet.url ; c.http(:get)
|
|
923
1718
|
end
|
|
924
1719
|
|
|
925
1720
|
assert_raise RuntimeError do
|
|
926
|
-
c = Curl::Easy.new ; c.url =
|
|
1721
|
+
c = Curl::Easy.new ; c.url = TestServlet.url ; c.http(FooNoToS.new)
|
|
927
1722
|
end
|
|
928
1723
|
|
|
929
1724
|
end
|
|
@@ -962,8 +1757,8 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
962
1757
|
curl.headers['Accept'] = '*/*'
|
|
963
1758
|
curl.headers['Authorization'] = 'Foo Bar Biz Baz'
|
|
964
1759
|
curl.http_put(rd)
|
|
965
|
-
assert_match
|
|
966
|
-
assert_match
|
|
1760
|
+
assert_match(/^PUT/, curl.body_str)
|
|
1761
|
+
assert_match(/hello$/, curl.body_str)
|
|
967
1762
|
curl.header_str
|
|
968
1763
|
curl.body_str
|
|
969
1764
|
end
|
|
@@ -996,7 +1791,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
996
1791
|
c = Curl::Easy.new($TEST_URL)
|
|
997
1792
|
c.on_success {|x| raise "error" }
|
|
998
1793
|
c.perform
|
|
999
|
-
rescue => e
|
|
1794
|
+
rescue Curl::Err::AbortedByCallbackError => e
|
|
1000
1795
|
assert_equal 'Curl::Err::AbortedByCallbackError', e.class.to_s
|
|
1001
1796
|
c.close
|
|
1002
1797
|
end
|
|
@@ -1022,6 +1817,130 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
1022
1817
|
end
|
|
1023
1818
|
end
|
|
1024
1819
|
|
|
1820
|
+
def test_close_during_http_post_argument_coercion_is_blocked
|
|
1821
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1822
|
+
field = Object.new
|
|
1823
|
+
field.define_singleton_method(:to_s) do
|
|
1824
|
+
curl.close
|
|
1825
|
+
"a=b"
|
|
1826
|
+
end
|
|
1827
|
+
|
|
1828
|
+
error = assert_raise(RuntimeError) { curl.http_post(field) }
|
|
1829
|
+
assert_match(/Cannot close an active curl handle/, error.message)
|
|
1830
|
+
|
|
1831
|
+
assert_nothing_raised { curl.close }
|
|
1832
|
+
end
|
|
1833
|
+
|
|
1834
|
+
def test_close_during_url_coercion_is_blocked
|
|
1835
|
+
curl = Curl::Easy.new
|
|
1836
|
+
url = Object.new
|
|
1837
|
+
url.define_singleton_method(:to_str) do
|
|
1838
|
+
curl.close
|
|
1839
|
+
TestServlet.url
|
|
1840
|
+
end
|
|
1841
|
+
|
|
1842
|
+
curl.url = url
|
|
1843
|
+
error = assert_raise(RuntimeError) { curl.perform }
|
|
1844
|
+
assert_match(/Cannot close an active curl handle/, error.message)
|
|
1845
|
+
|
|
1846
|
+
assert_nothing_raised { curl.close }
|
|
1847
|
+
end
|
|
1848
|
+
|
|
1849
|
+
def test_close_in_on_progress_is_blocked
|
|
1850
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1851
|
+
did_raise = false
|
|
1852
|
+
|
|
1853
|
+
curl.on_progress do |_dltotal, _dlnow, _ultotal, _ulnow|
|
|
1854
|
+
unless did_raise
|
|
1855
|
+
begin
|
|
1856
|
+
curl.close
|
|
1857
|
+
rescue RuntimeError
|
|
1858
|
+
did_raise = true
|
|
1859
|
+
end
|
|
1860
|
+
end
|
|
1861
|
+
true
|
|
1862
|
+
end
|
|
1863
|
+
|
|
1864
|
+
curl.perform
|
|
1865
|
+
assert did_raise
|
|
1866
|
+
end
|
|
1867
|
+
|
|
1868
|
+
def test_close_in_on_debug_is_blocked
|
|
1869
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1870
|
+
did_raise = false
|
|
1871
|
+
|
|
1872
|
+
curl.on_debug do |_type, _data|
|
|
1873
|
+
unless did_raise
|
|
1874
|
+
begin
|
|
1875
|
+
curl.close
|
|
1876
|
+
rescue RuntimeError
|
|
1877
|
+
did_raise = true
|
|
1878
|
+
end
|
|
1879
|
+
end
|
|
1880
|
+
end
|
|
1881
|
+
|
|
1882
|
+
curl.perform
|
|
1883
|
+
assert did_raise
|
|
1884
|
+
end
|
|
1885
|
+
|
|
1886
|
+
def test_close_in_upload_read_is_blocked
|
|
1887
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1888
|
+
|
|
1889
|
+
reader_class = Class.new do
|
|
1890
|
+
attr_reader :close_blocked
|
|
1891
|
+
|
|
1892
|
+
def initialize(curl)
|
|
1893
|
+
@curl = curl
|
|
1894
|
+
@done = false
|
|
1895
|
+
@close_blocked = false
|
|
1896
|
+
end
|
|
1897
|
+
|
|
1898
|
+
def read(_len)
|
|
1899
|
+
return nil if @done
|
|
1900
|
+
|
|
1901
|
+
@done = true
|
|
1902
|
+
begin
|
|
1903
|
+
@curl.close
|
|
1904
|
+
rescue RuntimeError
|
|
1905
|
+
@close_blocked = true
|
|
1906
|
+
end
|
|
1907
|
+
|
|
1908
|
+
'hello'
|
|
1909
|
+
end
|
|
1910
|
+
|
|
1911
|
+
def seek(_offset, _whence = SEEK_SET)
|
|
1912
|
+
0
|
|
1913
|
+
end
|
|
1914
|
+
|
|
1915
|
+
def stat
|
|
1916
|
+
Struct.new(:size).new(5)
|
|
1917
|
+
end
|
|
1918
|
+
end
|
|
1919
|
+
|
|
1920
|
+
reader = reader_class.new(curl)
|
|
1921
|
+
curl.http_put(reader)
|
|
1922
|
+
|
|
1923
|
+
assert reader.close_blocked
|
|
1924
|
+
assert_equal "PUT\nhello", curl.body_str
|
|
1925
|
+
end
|
|
1926
|
+
|
|
1927
|
+
def test_set_unsupported_options
|
|
1928
|
+
curl = Curl::Easy.new
|
|
1929
|
+
assert_raises TypeError do
|
|
1930
|
+
curl.set(99999, 1)
|
|
1931
|
+
end
|
|
1932
|
+
end
|
|
1933
|
+
|
|
1934
|
+
def test_poison
|
|
1935
|
+
res_a = Curl.get("#{TestServlet.url}?a_body")
|
|
1936
|
+
first_a_body = Digest::MD5.hexdigest(res_a.body)
|
|
1937
|
+
res_b = Curl.get("#{TestServlet.url}?b_body")
|
|
1938
|
+
|
|
1939
|
+
b_body = Digest::MD5.hexdigest(res_b.body)
|
|
1940
|
+
a_body = Digest::MD5.hexdigest(res_a.body)
|
|
1941
|
+
assert_not_equal a_body, b_body, "we expected #{a_body} to be #{first_a_body}"
|
|
1942
|
+
end
|
|
1943
|
+
|
|
1025
1944
|
include TestServerMethods
|
|
1026
1945
|
|
|
1027
1946
|
def setup
|