curb 0.8.4 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +522 -0
  3. data/Rakefile +79 -26
  4. data/ext/banned.h +32 -0
  5. data/ext/curb.c +549 -230
  6. data/ext/curb.h +19 -10
  7. data/ext/curb_easy.c +1935 -366
  8. data/ext/curb_easy.h +16 -0
  9. data/ext/curb_errors.c +115 -18
  10. data/ext/curb_errors.h +8 -5
  11. data/ext/curb_macros.h +33 -21
  12. data/ext/curb_multi.c +1858 -272
  13. data/ext/curb_multi.h +10 -3
  14. data/ext/curb_postfield.c +149 -77
  15. data/ext/curb_postfield.h +1 -0
  16. data/ext/curb_upload.c +38 -11
  17. data/ext/curb_upload.h +2 -0
  18. data/ext/extconf.rb +353 -35
  19. data/lib/curb.rb +1 -0
  20. data/lib/curl/easy.rb +314 -78
  21. data/lib/curl/multi.rb +134 -28
  22. data/lib/curl.rb +217 -11
  23. data/tests/bug_crash_on_debug.rb +14 -28
  24. data/tests/bug_crash_on_progress.rb +32 -16
  25. data/tests/bug_curb_easy_blocks_ruby_threads.rb +10 -15
  26. data/tests/bug_curb_easy_post_with_string_no_content_length_header.rb +6 -30
  27. data/tests/bug_follow_redirect_288.rb +83 -0
  28. data/tests/bug_instance_post_differs_from_class_post.rb +3 -5
  29. data/tests/bug_issue102.rb +1 -1
  30. data/tests/bug_issue_noproxy.rb +56 -0
  31. data/tests/bug_issue_post_redirect.rb +93 -0
  32. data/tests/bug_issue_spnego.rb +41 -0
  33. data/tests/bug_multi_segfault.rb +1 -0
  34. data/tests/bug_raise_on_callback.rb +30 -0
  35. data/tests/helper.rb +400 -44
  36. data/tests/leak_trace.rb +237 -0
  37. data/tests/mem_check.rb +3 -0
  38. data/tests/tc_curl.rb +31 -1
  39. data/tests/tc_curl_download.rb +12 -7
  40. data/tests/tc_curl_easy.rb +911 -63
  41. data/tests/tc_curl_easy_cookielist.rb +277 -0
  42. data/tests/tc_curl_easy_request_target.rb +41 -0
  43. data/tests/tc_curl_easy_resolve.rb +48 -0
  44. data/tests/tc_curl_maxfilesize.rb +12 -0
  45. data/tests/tc_curl_multi.rb +855 -53
  46. data/tests/tc_curl_native_coverage.rb +145 -0
  47. data/tests/tc_curl_postfield.rb +207 -30
  48. data/tests/tc_curl_protocols.rb +37 -0
  49. data/tests/tc_fiber_scheduler.rb +543 -0
  50. data/tests/tc_ftp_options.rb +39 -0
  51. data/tests/tc_gc_compact.rb +223 -0
  52. data/tests/tc_test_server_methods.rb +110 -0
  53. data/tests/timeout.rb +30 -6
  54. metadata +59 -36
  55. data/README +0 -194
@@ -0,0 +1,145 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
+
3
+ class TestCurbCurlErrorMappings < Test::Unit::TestCase
4
+ def assert_easy_error_mapping(code, expected_class)
5
+ actual_class, message = Curl::Easy.error(code)
6
+
7
+ assert_equal expected_class, actual_class
8
+ assert_kind_of String, message
9
+ assert_not_empty message
10
+ end
11
+
12
+ def test_easy_error_known_mappings
13
+ assert_easy_error_mapping(0, Curl::Err::CurlOK)
14
+ assert_easy_error_mapping(1, Curl::Err::UnsupportedProtocolError)
15
+ assert_easy_error_mapping(2, Curl::Err::FailedInitError)
16
+ assert_easy_error_mapping(3, Curl::Err::MalformedURLError)
17
+ assert_easy_error_mapping(5, Curl::Err::ProxyResolutionError)
18
+ assert_easy_error_mapping(6, Curl::Err::HostResolutionError)
19
+ assert_easy_error_mapping(7, Curl::Err::ConnectionFailedError)
20
+ assert_easy_error_mapping(23, Curl::Err::WriteError)
21
+ assert_easy_error_mapping(26, Curl::Err::ReadError)
22
+ assert_easy_error_mapping(28, Curl::Err::TimeoutError)
23
+ assert_easy_error_mapping(42, Curl::Err::AbortedByCallbackError)
24
+ assert_easy_error_mapping(47, Curl::Err::TooManyRedirectsError)
25
+ assert_easy_error_mapping(52, Curl::Err::GotNothingError)
26
+ assert_easy_error_mapping(55, Curl::Err::SendError)
27
+ assert_easy_error_mapping(56, Curl::Err::RecvError)
28
+ assert_easy_error_mapping(57, Curl::Err::ShareInUseError)
29
+ assert_easy_error_mapping(58, Curl::Err::SSLCertificateError)
30
+ assert_easy_error_mapping(59, Curl::Err::SSLCypherError)
31
+ assert_easy_error_mapping(61, Curl::Err::BadContentEncodingError)
32
+ assert_easy_error_mapping(63, Curl::Err::FileSizeExceededError)
33
+ assert_easy_error_mapping(64, Curl::Err::FTPSSLFailed)
34
+
35
+ ssl_peer_or_ca_error =
36
+ if Gem::Version.new(Curl::CURL_VERSION) >= Gem::Version.new('7.62.0')
37
+ Curl::Err::SSLPeerCertificateError
38
+ else
39
+ Curl::Err::SSLCACertificateError
40
+ end
41
+
42
+ assert_easy_error_mapping(60, ssl_peer_or_ca_error)
43
+ end
44
+
45
+ def test_easy_error_returns_error_info_for_known_numeric_range
46
+ 0.upto(92) do |code|
47
+ error_class, message = Curl::Easy.error(code)
48
+
49
+ assert_kind_of Class, error_class
50
+ assert error_class <= Curl::Err::CurlError
51
+ assert_kind_of String, message
52
+ assert_not_empty message
53
+ end
54
+ end
55
+
56
+ def test_easy_error_uses_generic_mapping_for_unknown_codes
57
+ error_class, message = Curl::Easy.error(9_999)
58
+
59
+ assert_equal Curl::Err::CurlError, error_class
60
+ assert_equal 'Unknown error result from libcurl', message
61
+ end
62
+ end
63
+
64
+ class TestCurbCurlNativeCoverage < Test::Unit::TestCase
65
+ include TestServerMethods
66
+
67
+ def setup
68
+ server_setup
69
+ end
70
+
71
+ def test_clone_preserves_native_lists_after_original_handle_closes
72
+ easy = Curl::Easy.new("http://curb.invalid:#{TestServlet.port}#{TestServlet.path}")
73
+ easy.headers['X-Test'] = '1'
74
+ easy.proxy_headers['X-Proxy'] = '2'
75
+ easy.ftp_commands = ['PWD']
76
+ easy.resolve = ["curb.invalid:#{TestServlet.port}:127.0.0.1"]
77
+
78
+ clone = easy.clone
79
+ easy.close
80
+
81
+ clone.http_get
82
+
83
+ assert_equal 'GET', clone.body_str
84
+ assert_equal '1', clone.headers['X-Test']
85
+ assert_equal '2', clone.proxy_headers['X-Proxy']
86
+ assert_equal ['PWD'], clone.ftp_commands
87
+ assert_equal ["curb.invalid:#{TestServlet.port}:127.0.0.1"], clone.resolve
88
+ ensure
89
+ clone.close if defined?(clone) && clone
90
+ easy.close if defined?(easy) && easy
91
+ end
92
+
93
+ def test_clone_rebinds_upload_callbacks_to_clone_state
94
+ easy = Curl::Easy.new(TestServlet.url)
95
+ easy.put_data = 'clone-data'
96
+
97
+ clone = easy.clone
98
+ easy.put_data = 'other-data'
99
+
100
+ clone.perform
101
+
102
+ assert_equal "PUT\nclone-data", clone.body_str
103
+ ensure
104
+ clone.close if defined?(clone) && clone
105
+ easy.close if defined?(easy) && easy
106
+ end
107
+
108
+ def test_native_accessors_round_trip
109
+ easy = Curl::Easy.new(TestServlet.url)
110
+
111
+ assert_equal '127.0.0.1', easy.interface = '127.0.0.1'
112
+ assert_equal 'user:pass', easy.userpwd = 'user:pass'
113
+ assert_equal 'proxy:pass', easy.proxypwd = 'proxy:pass'
114
+ assert_equal 'tests/cert.pem', easy.cert_key = 'tests/cert.pem'
115
+ assert_equal 'gzip', easy.encoding = 'gzip'
116
+
117
+ if easy.respond_to?(:max_send_speed_large=)
118
+ assert_equal 123, easy.max_send_speed_large = 123
119
+ assert_equal 123, easy.max_send_speed_large
120
+ end
121
+
122
+ if easy.respond_to?(:max_recv_speed_large=)
123
+ assert_equal 456, easy.max_recv_speed_large = 456
124
+ assert_equal 456, easy.max_recv_speed_large
125
+ end
126
+
127
+ assert_equal '127.0.0.1', easy.interface
128
+ assert_equal 'user:pass', easy.userpwd
129
+ assert_equal 'proxy:pass', easy.proxypwd
130
+ assert_equal 'tests/cert.pem', easy.cert_key
131
+ assert_equal 'gzip', easy.encoding
132
+ ensure
133
+ easy.close if defined?(easy) && easy
134
+ end
135
+
136
+ def test_upload_round_trips_stream_and_offset
137
+ upload = Curl::Upload.new
138
+ stream = StringIO.new('payload')
139
+
140
+ assert_same stream, upload.stream = stream
141
+ assert_same stream, upload.stream
142
+ assert_equal 7, upload.offset = 7
143
+ assert_equal 7, upload.offset
144
+ end
145
+ end
@@ -2,109 +2,110 @@ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
2
 
3
3
  class TestCurbCurlPostfield < Test::Unit::TestCase
4
4
  def test_private_new
5
- assert_raise(NoMethodError) { Curl::PostField.new }
5
+ assert_raise(NoMethodError) { Curl::PostField.new }
6
6
  end
7
-
7
+
8
8
  def test_new_content_01
9
9
  pf = Curl::PostField.content('foo', 'bar')
10
-
10
+
11
11
  assert_equal 'foo', pf.name
12
12
  assert_equal 'bar', pf.content
13
13
  assert_nil pf.content_type
14
14
  assert_nil pf.local_file
15
- assert_nil pf.remote_file
15
+ assert_nil pf.remote_file
16
16
  assert_nil pf.set_content_proc
17
17
  end
18
-
18
+
19
19
  def test_new_content_02
20
20
  pf = Curl::PostField.content('foo', 'bar', 'text/html')
21
-
21
+
22
22
  assert_equal 'foo', pf.name
23
23
  assert_equal 'bar', pf.content
24
24
  assert_equal 'text/html', pf.content_type
25
25
  assert_nil pf.local_file
26
26
  assert_nil pf.remote_file
27
- assert_nil pf.set_content_proc
28
- end
29
-
27
+ assert_nil pf.set_content_proc
28
+ end
29
+
30
30
  def test_new_content_03
31
31
  l = lambda { |field| "never gets run" }
32
32
  pf = Curl::PostField.content('foo', &l)
33
-
33
+
34
34
  assert_equal 'foo', pf.name
35
35
  assert_nil pf.content
36
36
  assert_nil pf.content_type
37
37
  assert_nil pf.local_file
38
38
  assert_nil pf.remote_file
39
-
39
+
40
40
  # N.B. This doesn't just get the proc, but also removes it.
41
41
  assert_equal l, pf.set_content_proc
42
- end
42
+ end
43
43
 
44
44
  def test_new_content_04
45
45
  l = lambda { |field| "never gets run" }
46
46
  pf = Curl::PostField.content('foo', 'text/html', &l)
47
-
47
+
48
48
  assert_equal 'foo', pf.name
49
49
  assert_nil pf.content
50
50
  assert_equal 'text/html', pf.content_type
51
51
  assert_nil pf.local_file
52
52
  assert_nil pf.remote_file
53
-
53
+
54
54
  # N.B. This doesn't just get the proc, but also removes it.
55
55
  assert_equal l, pf.set_content_proc
56
- end
56
+ end
57
57
 
58
58
 
59
59
  def test_new_file_01
60
60
  pf = Curl::PostField.file('foo', 'localname')
61
-
61
+ pf.content_type = 'text/super'
62
+
62
63
  assert_equal 'foo', pf.name
63
64
  assert_equal 'localname', pf.local_file
64
65
  assert_equal 'localname', pf.remote_file
65
66
  assert_nothing_raised { pf.to_s }
66
- assert_nil pf.content_type
67
+ assert_equal 'text/super', pf.content_type
67
68
  assert_nil pf.content
68
69
  assert_nil pf.set_content_proc
69
70
  end
70
-
71
+
71
72
  def test_new_file_02
72
73
  pf = Curl::PostField.file('foo', 'localname', 'remotename')
73
-
74
+
74
75
  assert_equal 'foo', pf.name
75
76
  assert_equal 'localname', pf.local_file
76
77
  assert_equal 'remotename', pf.remote_file
77
78
  assert_nil pf.content_type
78
79
  assert_nil pf.content
79
80
  assert_nil pf.set_content_proc
80
- end
81
-
81
+ end
82
+
82
83
  def test_new_file_03
83
84
  l = lambda { |field| "never gets run" }
84
85
  pf = Curl::PostField.file('foo', 'remotename', &l)
85
-
86
+
86
87
  assert_equal 'foo', pf.name
87
88
  assert_equal 'remotename', pf.remote_file
88
89
  assert_nil pf.local_file
89
90
  assert_nil pf.content_type
90
91
  assert_nil pf.content
91
-
92
+
92
93
  # N.B. This doesn't just get the proc, but also removes it.
93
94
  assert_equal l, pf.set_content_proc
94
- end
95
+ end
95
96
 
96
97
  def test_new_file_04
97
98
  assert_raise(ArgumentError) do
98
99
  # no local name, no block
99
100
  Curl::PostField.file('foo')
100
101
  end
101
-
102
+
102
103
  assert_raise(ArgumentError) do
103
104
  # no remote name with block
104
105
  Curl::PostField.file('foo') { |field| "never runs" }
105
106
  end
106
107
  end
107
-
108
+
108
109
  def test_new_file_05
109
110
  # local gets ignored when supplying a block, but remote
110
111
  # is still set up properly.
@@ -118,15 +119,15 @@ class TestCurbCurlPostfield < Test::Unit::TestCase
118
119
  assert_nil pf.content
119
120
 
120
121
  assert_equal l, pf.set_content_proc
121
- end
122
-
122
+ end
123
+
123
124
  def test_to_s_01
124
- pf = Curl::PostField.content('foo', 'bar')
125
+ pf = Curl::PostField.content('foo', 'bar')
125
126
  assert_equal "foo=bar", pf.to_s
126
127
  end
127
128
 
128
129
  def test_to_s_02
129
- pf = Curl::PostField.content('foo', 'bar ton')
130
+ pf = Curl::PostField.content('foo', 'bar ton')
130
131
  assert_equal "foo=bar%20ton", pf.to_s
131
132
  end
132
133
 
@@ -135,9 +136,185 @@ class TestCurbCurlPostfield < Test::Unit::TestCase
135
136
  assert_equal "foo=FOOBAR", pf.to_s
136
137
  end
137
138
 
139
+ def test_content_proc_survives_gc
140
+ pf = postfield_with_only_native_proc_reference
141
+
142
+ 10.times do
143
+ GC.start(full_mark: true, immediate_sweep: true)
144
+ GC.compact if GC.respond_to?(:compact)
145
+ end
146
+
147
+ assert_equal "foo=FOOBAR", pf.to_s
148
+ end
149
+
138
150
  def test_to_s_04
139
151
  pf = Curl::PostField.file('foo.file', 'bar.file')
140
152
  assert_nothing_raised { pf.to_s }
141
153
  #assert_raise(Curl::Err::InvalidPostFieldError) { pf.to_s }
142
154
  end
155
+
156
+ def postfield_with_only_native_proc_reference
157
+ Curl::PostField.content('foo') { |field| field.name.upcase + "BAR" }
158
+ end
159
+ end
160
+
161
+ class TestCurbCurlPostfieldNativeCoverage < Test::Unit::TestCase
162
+ def test_attribute_writers_round_trip
163
+ pf = Curl::PostField.content('foo', 'bar')
164
+
165
+ assert_equal 'renamed', pf.name = 'renamed'
166
+ assert_equal 'payload', pf.content = 'payload'
167
+ assert_equal 'text/plain', pf.content_type = 'text/plain'
168
+ assert_equal 'local.txt', pf.local_file = 'local.txt'
169
+ assert_equal 'remote.txt', pf.remote_file = 'remote.txt'
170
+
171
+ assert_equal 'renamed', pf.name
172
+ assert_equal 'payload', pf.content
173
+ assert_equal 'text/plain', pf.content_type
174
+ assert_equal 'local.txt', pf.local_file
175
+ assert_equal 'remote.txt', pf.remote_file
176
+ end
177
+
178
+ def test_to_s_accepts_non_string_name_via_to_s
179
+ name_like = Object.new
180
+ def name_like.to_s
181
+ 'fancy name'
182
+ end
183
+
184
+ pf = Curl::PostField.content(name_like, 'value')
185
+ assert_equal 'fancy%20name=value', pf.to_s
186
+ end
187
+
188
+ def test_to_s_uses_remote_file_when_local_file_is_missing
189
+ pf = Curl::PostField.file('upload', 'local.txt', 'remote.txt')
190
+ pf.local_file = nil
191
+
192
+ assert_equal 'upload=remote.txt', pf.to_s
193
+ end
194
+
195
+ def test_to_s_rejects_name_without_to_s
196
+ name_like = Class.new do
197
+ undef to_s
198
+ end.new
199
+
200
+ pf = Curl::PostField.content(name_like, 'value')
201
+
202
+ error = assert_raise(Curl::Err::InvalidPostFieldError) { pf.to_s }
203
+ assert_match(/Cannot convert unnamed field to string/, error.message)
204
+ end
205
+
206
+ def test_to_s_rejects_content_without_to_s
207
+ content_like = Class.new do
208
+ undef to_s
209
+ end.new
210
+
211
+ pf = Curl::PostField.content('name', content_like)
212
+
213
+ error = assert_raise(RuntimeError) { pf.to_s }
214
+ assert_match(/does not respond_to to_s/, error.message)
215
+ end
216
+
217
+ def test_multipart_rejects_unnamed_field
218
+ curl = Curl::Easy.new(TestServlet.url)
219
+ curl.multipart_form_post = true
220
+ pf = Curl::PostField.content('name', 'value')
221
+ pf.name = nil
222
+
223
+ error = assert_raise(Curl::Err::InvalidPostFieldError) { curl.http_post(pf) }
224
+ assert_match(/Cannot post unnamed field/, error.message)
225
+ end
226
+
227
+ def test_multipart_rejects_content_field_without_data
228
+ curl = Curl::Easy.new(TestServlet.url)
229
+ curl.multipart_form_post = true
230
+ pf = Curl::PostField.content('name', 'value')
231
+ pf.content = nil
232
+
233
+ error = assert_raise(Curl::Err::InvalidPostFieldError) { curl.http_post(pf) }
234
+ assert_match(/Cannot post content field with no data/, error.message)
235
+ end
236
+
237
+ def test_multipart_rejects_file_field_without_filename
238
+ curl = Curl::Easy.new(TestServlet.url)
239
+ curl.multipart_form_post = true
240
+ pf = Curl::PostField.file('upload', 'remote.txt') { 'payload' }
241
+ pf.local_file = 'dummy.txt'
242
+ pf.remote_file = nil
243
+
244
+ error = assert_raise(Curl::Err::InvalidPostFieldError) { curl.http_post(pf) }
245
+ assert_match(/Cannot post file upload field with no filename/, error.message)
246
+ end
247
+ end
248
+
249
+ class TestCurbCurlPostfieldMultipartCoverage < Test::Unit::TestCase
250
+ include TestServerMethods
251
+
252
+ def setup
253
+ server_setup
254
+ end
255
+
256
+ def test_multipart_content_variants_include_dynamic_and_typed_fields
257
+ curl = Curl::Easy.new(TestServlet.url)
258
+ curl.multipart_form_post = true
259
+
260
+ proc_without_type = Curl::PostField.content('proc_without_type') { 'alpha' }
261
+ proc_with_type = Curl::PostField.content('proc_with_type', 'text/plain') { 'beta' }
262
+ direct_with_type = Curl::PostField.content('direct_with_type', 'gamma', 'text/plain')
263
+
264
+ curl.http_post([proc_without_type, proc_with_type, direct_with_type])
265
+ body = curl.body_str
266
+
267
+ assert_match(/name="proc_without_type"/, body)
268
+ assert_match(/alpha/, body)
269
+ assert_match(/name="proc_with_type"/, body)
270
+ assert_match(/beta/, body)
271
+ assert_match(/name="direct_with_type"/, body)
272
+ assert_match(/gamma/, body)
273
+ assert_match(/Content-Type: text\/plain/, body)
274
+ end
275
+
276
+ def test_multipart_file_variants_include_buffered_and_local_uploads
277
+ readme = File.expand_path(File.join(File.dirname(__FILE__), '..', 'README.md'))
278
+
279
+ proc_without_type = Curl::PostField.file('proc_without_type', 'proc_without_type.txt') { 'alpha' }
280
+ proc_with_type = Curl::PostField.file('proc_with_type', 'proc_with_type.txt') { 'beta' }
281
+ proc_with_type.content_type = 'text/plain'
282
+
283
+ direct_without_type = Curl::PostField.file('direct_without_type', 'ignored.txt', 'direct_without_type.txt')
284
+ direct_without_type.content = 'gamma'
285
+ direct_without_type.local_file = nil
286
+
287
+ direct_with_type = Curl::PostField.file('direct_with_type', 'ignored.txt', 'direct_with_type.txt')
288
+ direct_with_type.content = 'delta'
289
+ direct_with_type.local_file = nil
290
+ direct_with_type.content_type = 'text/plain'
291
+
292
+ local_with_type = Curl::PostField.file('local_with_type', readme)
293
+ local_with_type.content_type = 'text/plain'
294
+
295
+ curl = Curl::Easy.new(TestServlet.url)
296
+ curl.multipart_form_post = true
297
+ curl.http_post([proc_without_type, proc_with_type, direct_without_type, direct_with_type, local_with_type])
298
+ body = curl.body_str
299
+
300
+ assert_match(/name="proc_without_type"/, body)
301
+ assert_match(/filename="proc_without_type.txt"/, body)
302
+ assert_match(/alpha/, body)
303
+
304
+ assert_match(/name="proc_with_type"/, body)
305
+ assert_match(/filename="proc_with_type.txt"/, body)
306
+ assert_match(/beta/, body)
307
+
308
+ assert_match(/name="direct_without_type"/, body)
309
+ assert_match(/filename="direct_without_type.txt"/, body)
310
+ assert_match(/gamma/, body)
311
+
312
+ assert_match(/name="direct_with_type"/, body)
313
+ assert_match(/filename="direct_with_type.txt"/, body)
314
+ assert_match(/delta/, body)
315
+
316
+ assert_match(/name="local_with_type"/, body)
317
+ assert_match(/Curb - Libcurl bindings for Ruby/, body)
318
+ assert_match(/Content-Type: text\/plain/, body)
319
+ end
143
320
  end
@@ -0,0 +1,37 @@
1
+ class TestCurbCurlProtocols < Test::Unit::TestCase
2
+ include TestServerMethods
3
+
4
+ def setup
5
+ @easy = Curl::Easy.new
6
+ @easy.set :protocols, Curl::CURLPROTO_HTTP | Curl::CURLPROTO_HTTPS
7
+ @easy.follow_location = true
8
+ server_setup
9
+ end
10
+
11
+ def test_protocol_allowed
12
+ @easy.set :url, "http://127.0.0.1:9129/this_file_does_not_exist.html"
13
+ @easy.perform
14
+ assert_equal 404, @easy.response_code
15
+ end
16
+
17
+ def test_protocol_denied
18
+ @easy.set :url, "gopher://google.com/"
19
+ assert_raises Curl::Err::UnsupportedProtocolError do
20
+ @easy.perform
21
+ end
22
+ end
23
+
24
+ def test_redir_protocol_allowed
25
+ @easy.set :url, TestServlet.url + "/redirect"
26
+ @easy.set :redir_protocols, Curl::CURLPROTO_HTTP
27
+ @easy.perform
28
+ end
29
+
30
+ def test_redir_protocol_denied
31
+ @easy.set :url, TestServlet.url + "/redirect"
32
+ @easy.set :redir_protocols, Curl::CURLPROTO_HTTPS
33
+ assert_raises Curl::Err::UnsupportedProtocolError do
34
+ @easy.perform
35
+ end
36
+ end
37
+ end