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
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
class TestCurbCurlEasyCookielist < Test::Unit::TestCase
|
|
5
|
+
def test_setopt_cookielist
|
|
6
|
+
easy = Curl::Easy.new
|
|
7
|
+
# DateTime handles time zone correctly
|
|
8
|
+
expires = (Date.today + 2).to_datetime
|
|
9
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, "Set-Cookie: c1=v1; domain=localhost; expires=#{expires.httpdate};")
|
|
10
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'Set-Cookie: c2=v2; domain=localhost')
|
|
11
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, "Set-Cookie: c3=v3; expires=#{expires.httpdate};")
|
|
12
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'Set-Cookie: c4=v4;')
|
|
13
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, "Set-Cookie: c5=v5; domain=127.0.0.1; expires=#{expires.httpdate};")
|
|
14
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'Set-Cookie: c6=v6; domain=127.0.0.1;;')
|
|
15
|
+
|
|
16
|
+
# Since 7.43.0 cookies that were imported in the Set-Cookie format without a domain name are not exported by this option.
|
|
17
|
+
# So, before 7.43.0, c3 and c4 will be exported too; but that version is far too old for current curb version, so it's not handled here.
|
|
18
|
+
if Curl::CURL_VERSION.to_f > 8
|
|
19
|
+
expected_cookielist = [
|
|
20
|
+
".127.0.0.1\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tc5\tv5",
|
|
21
|
+
".127.0.0.1\tTRUE\t/\tFALSE\t0\tc6\tv6",
|
|
22
|
+
".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tc1\tv1",
|
|
23
|
+
".localhost\tTRUE\t/\tFALSE\t0\tc2\tv2",
|
|
24
|
+
]
|
|
25
|
+
else
|
|
26
|
+
expected_cookielist = [
|
|
27
|
+
"127.0.0.1\tFALSE\t/\tFALSE\t#{expires.to_time.to_i}\tc5\tv5",
|
|
28
|
+
"127.0.0.1\tFALSE\t/\tFALSE\t0\tc6\tv6",
|
|
29
|
+
".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tc1\tv1",
|
|
30
|
+
".localhost\tTRUE\t/\tFALSE\t0\tc2\tv2",
|
|
31
|
+
]
|
|
32
|
+
end
|
|
33
|
+
assert_equal expected_cookielist, easy.cookielist
|
|
34
|
+
|
|
35
|
+
easy.url = "#{TestServlet.url}/get_cookies"
|
|
36
|
+
easy.perform
|
|
37
|
+
assert_equal 'c6=v6; c5=v5; c4=v4; c3=v3', easy.body_str
|
|
38
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
|
39
|
+
easy.perform
|
|
40
|
+
assert_equal 'c2=v2; c1=v1', easy.body_str
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# libcurl documentation says: "This option also enables the cookie engine", but it's not tracked on the curb level
|
|
44
|
+
def test_setopt_cookielist_enables_cookie_engine
|
|
45
|
+
easy = Curl::Easy.new
|
|
46
|
+
expires = (Date.today + 2).to_datetime
|
|
47
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/set_cookies"
|
|
48
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, "Set-Cookie: c1=v1; domain=localhost; expires=#{expires.httpdate};")
|
|
49
|
+
easy.post_body = JSON.generate([{ name: 'c2', value: 'v2', domain: 'localhost', expires: expires.httpdate, path: '/' }])
|
|
50
|
+
easy.perform
|
|
51
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
|
52
|
+
easy.post_body = nil
|
|
53
|
+
easy.perform
|
|
54
|
+
|
|
55
|
+
assert !easy.enable_cookies?
|
|
56
|
+
assert_equal [".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tc1\tv1", ".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tc2\tv2"], easy.cookielist
|
|
57
|
+
assert_equal 'c2=v2; c1=v1', easy.body_str
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_setopt_cookielist_invalid_format
|
|
61
|
+
easy = Curl::Easy.new
|
|
62
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
|
63
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'Not a cookie')
|
|
64
|
+
assert_nil easy.cookielist
|
|
65
|
+
easy.perform
|
|
66
|
+
assert_equal '', easy.body_str
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_setopt_cookielist_netscape_format
|
|
70
|
+
easy = Curl::Easy.new
|
|
71
|
+
expires = (Date.today + 2).to_datetime
|
|
72
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
|
73
|
+
# Note domain changes for include subdomains
|
|
74
|
+
[
|
|
75
|
+
['localhost', 'FALSE', '/', 'TRUE', 0, 'session_http_only', '42'].join("\t"),
|
|
76
|
+
['.localhost', 'TRUE', '/', 'FALSE', 0, 'session', '43'].join("\t"),
|
|
77
|
+
['localhost', 'TRUE', '/', 'FALSE', expires.to_time.to_i, 'permanent', '44'].join("\t"),
|
|
78
|
+
['.localhost', 'FALSE', '/', 'TRUE', expires.to_time.to_i, 'permanent_http_only', '45'].join("\t"),
|
|
79
|
+
].each { |cookie| easy.setopt(Curl::CURLOPT_COOKIELIST, cookie) }
|
|
80
|
+
|
|
81
|
+
expected_cookielist = [
|
|
82
|
+
['localhost', 'FALSE', '/', 'TRUE', 0, 'session_http_only', '42'].join("\t"),
|
|
83
|
+
['.localhost', 'TRUE', '/', 'FALSE', 0, 'session', '43'].join("\t"),
|
|
84
|
+
['.localhost', 'TRUE', '/', 'FALSE', expires.to_time.to_i, 'permanent', '44'].join("\t"),
|
|
85
|
+
['localhost', 'FALSE', '/', 'TRUE', expires.to_time.to_i, 'permanent_http_only', '45'].join("\t"),
|
|
86
|
+
]
|
|
87
|
+
assert_equal expected_cookielist, easy.cookielist
|
|
88
|
+
easy.perform
|
|
89
|
+
assert_equal 'permanent_http_only=45; session_http_only=42; permanent=44; session=43', easy.body_str
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Multiple cookies and comments are not supported
|
|
93
|
+
def test_setopt_cookielist_netscape_format_mutliline
|
|
94
|
+
easy = Curl::Easy.new
|
|
95
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
|
96
|
+
easy.setopt(
|
|
97
|
+
Curl::CURLOPT_COOKIELIST,
|
|
98
|
+
[
|
|
99
|
+
'# Netscape HTTP Cookie File',
|
|
100
|
+
['.localhost', 'TRUE', '/', 'FALSE', 0, 'session', '42'].join("\t"),
|
|
101
|
+
'',
|
|
102
|
+
].join("\n"),
|
|
103
|
+
)
|
|
104
|
+
assert_nil easy.cookielist
|
|
105
|
+
easy.perform
|
|
106
|
+
assert_equal '', easy.body_str
|
|
107
|
+
|
|
108
|
+
easy.setopt(
|
|
109
|
+
Curl::CURLOPT_COOKIELIST,
|
|
110
|
+
[
|
|
111
|
+
['.localhost', 'TRUE', '/', 'FALSE', 0, 'session', '42'].join("\t"),
|
|
112
|
+
['.localhost', 'TRUE', '/', 'FALSE', 0, 'session2', '84'].join("\t"),
|
|
113
|
+
'',
|
|
114
|
+
].join("\n"),
|
|
115
|
+
)
|
|
116
|
+
# Only first cookie is set
|
|
117
|
+
assert_equal [".localhost\tTRUE\t/\tFALSE\t0\tsession\t42"], easy.cookielist
|
|
118
|
+
easy.perform
|
|
119
|
+
assert_equal 'session=42', easy.body_str
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# ALL erases all cookies held in memory
|
|
123
|
+
# ALL was added in 7.14.1
|
|
124
|
+
def test_setopt_cookielist_command_all
|
|
125
|
+
expires = (Date.today + 2).to_datetime
|
|
126
|
+
with_permanent_and_session_cookies(expires) do |easy|
|
|
127
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'ALL')
|
|
128
|
+
assert_nil easy.cookielist
|
|
129
|
+
easy.perform
|
|
130
|
+
assert_equal '', easy.body_str
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# SESS erases all session cookies held in memory
|
|
135
|
+
# SESS was added in 7.15.4
|
|
136
|
+
def test_setopt_cookielist_command_sess
|
|
137
|
+
expires = (Date.today + 2).to_datetime
|
|
138
|
+
with_permanent_and_session_cookies(expires) do |easy|
|
|
139
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'SESS')
|
|
140
|
+
assert_equal [".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tpermanent\t42"], easy.cookielist
|
|
141
|
+
easy.perform
|
|
142
|
+
assert_equal 'permanent=42', easy.body_str
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# FLUSH writes all known cookies to the file specified by CURLOPT_COOKIEJAR
|
|
147
|
+
# FLUSH was added in 7.17.1
|
|
148
|
+
def test_setopt_cookielist_command_flush
|
|
149
|
+
expires = (Date.today + 2).to_datetime
|
|
150
|
+
with_permanent_and_session_cookies(expires) do |easy|
|
|
151
|
+
cookiejar = File.join(Dir.tmpdir, 'curl_test_cookiejar')
|
|
152
|
+
assert !File.exist?(cookiejar)
|
|
153
|
+
begin
|
|
154
|
+
easy.cookiejar = cookiejar
|
|
155
|
+
# trick to actually set CURLOPT_COOKIEJAR
|
|
156
|
+
easy.enable_cookies = true
|
|
157
|
+
easy.perform
|
|
158
|
+
assert !File.exist?(cookiejar)
|
|
159
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'FLUSH')
|
|
160
|
+
expected_cookiejar = <<~COOKIEJAR
|
|
161
|
+
# Netscape HTTP Cookie File
|
|
162
|
+
# https://curl.se/docs/http-cookies.html
|
|
163
|
+
# This file was generated by libcurl! Edit at your own risk.
|
|
164
|
+
|
|
165
|
+
.localhost TRUE / FALSE 0 session 420
|
|
166
|
+
.localhost TRUE / FALSE #{expires.to_time.to_i} permanent 42
|
|
167
|
+
COOKIEJAR
|
|
168
|
+
assert_equal expected_cookiejar, File.read(cookiejar)
|
|
169
|
+
ensure
|
|
170
|
+
# Otherwise it'll create this file again
|
|
171
|
+
easy.close
|
|
172
|
+
File.unlink(cookiejar) if File.exist?(cookiejar)
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# RELOAD loads all cookies from the files specified by CURLOPT_COOKIEFILE
|
|
178
|
+
# RELOAD was added in 7.39.0
|
|
179
|
+
def test_setopt_cookielist_command_reload
|
|
180
|
+
expires = (Date.today + 2).to_datetime
|
|
181
|
+
expires_file = (Date.today + 4).to_datetime
|
|
182
|
+
with_permanent_and_session_cookies(expires) do |easy|
|
|
183
|
+
cookiefile = File.join(Dir.tmpdir, 'curl_test_cookiefile')
|
|
184
|
+
assert !File.exist?(cookiefile)
|
|
185
|
+
begin
|
|
186
|
+
cookielist = [
|
|
187
|
+
# Won't be updated, added instead
|
|
188
|
+
".localhost\tTRUE\t/\tFALSE\t#{expires_file.to_time.to_i}\tpermanent\t84",
|
|
189
|
+
".localhost\tTRUE\t/\tFALSE\t#{expires_file.to_time.to_i}\tpermanent_file\t84",
|
|
190
|
+
# Won't be updated, added instead
|
|
191
|
+
".localhost\tTRUE\t/\tFALSE\t0\tsession\t840",
|
|
192
|
+
".localhost\tTRUE\t/\tFALSE\t0\tsession_file\t840",
|
|
193
|
+
'',
|
|
194
|
+
]
|
|
195
|
+
File.write(cookiefile, cookielist.join("\n"))
|
|
196
|
+
easy.cookiefile = cookiefile
|
|
197
|
+
# trick to actually set CURLOPT_COOKIEFILE
|
|
198
|
+
easy.enable_cookies = true
|
|
199
|
+
easy.perform
|
|
200
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'RELOAD')
|
|
201
|
+
expected_cookielist = [
|
|
202
|
+
".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tpermanent\t42",
|
|
203
|
+
".localhost\tTRUE\t/\tFALSE\t0\tsession\t420",
|
|
204
|
+
".localhost\tTRUE\t/\tFALSE\t#{expires_file.to_time.to_i}\tpermanent\t84",
|
|
205
|
+
".localhost\tTRUE\t/\tFALSE\t#{expires_file.to_time.to_i}\tpermanent_file\t84",
|
|
206
|
+
".localhost\tTRUE\t/\tFALSE\t0\tsession\t840",
|
|
207
|
+
".localhost\tTRUE\t/\tFALSE\t0\tsession_file\t840",
|
|
208
|
+
]
|
|
209
|
+
assert_equal expected_cookielist, easy.cookielist
|
|
210
|
+
easy.perform
|
|
211
|
+
# Be careful, duplicates are not removed
|
|
212
|
+
assert_equal 'permanent_file=84; session_file=840; permanent=84; session=840; permanent=42; session=420', easy.body_str
|
|
213
|
+
ensure
|
|
214
|
+
File.unlink(cookiefile) if File.exist?(cookiefile)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def test_commands_do_not_enable_cookie_engine
|
|
220
|
+
%w[ALL SESS FLUSH RELOAD].each do |command|
|
|
221
|
+
easy = Curl::Easy.new
|
|
222
|
+
expires = (Date.today + 2).to_datetime
|
|
223
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/set_cookies"
|
|
224
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, command)
|
|
225
|
+
easy.post_body = JSON.generate([{ name: 'c2', value: 'v2', domain: 'localhost', expires: expires.httpdate, path: '/' }])
|
|
226
|
+
easy.perform
|
|
227
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
|
228
|
+
easy.post_body = nil
|
|
229
|
+
easy.perform
|
|
230
|
+
|
|
231
|
+
assert !easy.enable_cookies?
|
|
232
|
+
assert_nil easy.cookielist
|
|
233
|
+
assert_equal '', easy.body_str
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def test_strings_without_cookie_enable_cookie_engine
|
|
239
|
+
[
|
|
240
|
+
'',
|
|
241
|
+
'# Netscape HTTP Cookie File',
|
|
242
|
+
'no_a_cookie',
|
|
243
|
+
].each do |command|
|
|
244
|
+
easy = Curl::Easy.new
|
|
245
|
+
expires = (Date.today + 2).to_datetime
|
|
246
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/set_cookies"
|
|
247
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, command)
|
|
248
|
+
easy.post_body = JSON.generate([{ name: 'c2', value: 'v2', domain: 'localhost', expires: expires.httpdate, path: '/' }])
|
|
249
|
+
easy.perform
|
|
250
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
|
251
|
+
easy.post_body = nil
|
|
252
|
+
easy.perform
|
|
253
|
+
|
|
254
|
+
assert !easy.enable_cookies?
|
|
255
|
+
assert_equal [".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tc2\tv2"], easy.cookielist
|
|
256
|
+
assert_equal 'c2=v2', easy.body_str
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def with_permanent_and_session_cookies(expires)
|
|
261
|
+
easy = Curl::Easy.new
|
|
262
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
|
263
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, "Set-Cookie: permanent=42; domain=localhost; expires=#{expires.httpdate};")
|
|
264
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'Set-Cookie: session=420; domain=localhost;')
|
|
265
|
+
assert_equal [".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tpermanent\t42", ".localhost\tTRUE\t/\tFALSE\t0\tsession\t420"], easy.cookielist
|
|
266
|
+
easy.perform
|
|
267
|
+
assert_equal 'permanent=42; session=420', easy.body_str
|
|
268
|
+
|
|
269
|
+
yield easy
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
include TestServerMethods
|
|
273
|
+
|
|
274
|
+
def setup
|
|
275
|
+
server_setup
|
|
276
|
+
end
|
|
277
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
|
2
|
+
|
|
3
|
+
class TestCurbCurlEasyRequestTarget < Test::Unit::TestCase
|
|
4
|
+
include TestServerMethods
|
|
5
|
+
|
|
6
|
+
def setup
|
|
7
|
+
server_setup
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def test_request_target_absolute_form
|
|
11
|
+
unless Curl.const_defined?(:CURLOPT_REQUEST_TARGET)
|
|
12
|
+
omit('libcurl lacks CURLOPT_REQUEST_TARGET support')
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
tmp = Tempfile.new('curb_test_request_target')
|
|
16
|
+
path = tmp.path
|
|
17
|
+
fd = IO.sysopen(path, 'w')
|
|
18
|
+
io = IO.new(fd, 'w')
|
|
19
|
+
io.sync = true
|
|
20
|
+
|
|
21
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
22
|
+
easy.verbose = true
|
|
23
|
+
easy.setopt(Curl::CURLOPT_STDERR, io)
|
|
24
|
+
|
|
25
|
+
# Force absolute-form request target, different from the URL host
|
|
26
|
+
easy.request_target = "http://localhost:#{TestServlet.port}#{TestServlet.path}"
|
|
27
|
+
easy.headers = { 'Host' => "example.com" }
|
|
28
|
+
|
|
29
|
+
easy.perform
|
|
30
|
+
|
|
31
|
+
io.flush
|
|
32
|
+
io.close
|
|
33
|
+
output = File.read(path)
|
|
34
|
+
|
|
35
|
+
assert_match(/GET\s+http:\/\/localhost:#{TestServlet.port}#{Regexp.escape(TestServlet.path)}\s+HTTP\/1\.1/, output)
|
|
36
|
+
assert_match(/Host:\s+example\.com/, output)
|
|
37
|
+
ensure
|
|
38
|
+
tmp.close! if defined?(tmp) && tmp
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
|
2
|
+
|
|
3
|
+
class TestCurbCurlEasyResolve < Test::Unit::TestCase
|
|
4
|
+
include TestServerMethods
|
|
5
|
+
|
|
6
|
+
def setup
|
|
7
|
+
server_setup
|
|
8
|
+
@easy = Curl::Easy.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def test_resolve
|
|
12
|
+
@easy.resolve = [ "example.com:80:127.0.0.1" ]
|
|
13
|
+
assert_equal @easy.resolve, [ "example.com:80:127.0.0.1" ]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_empty_resolve
|
|
17
|
+
assert_equal @easy.resolve, nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_setopt_resolve_persists_across_performs
|
|
21
|
+
host = "curb-setopt-resolve.invalid"
|
|
22
|
+
mapping = "#{host}:#{TestServlet.port}:127.0.0.1"
|
|
23
|
+
|
|
24
|
+
@easy.url = "http://#{host}:#{TestServlet.port}#{TestServlet.path}"
|
|
25
|
+
@easy.dns_cache_timeout = 0
|
|
26
|
+
@easy.set(:resolve, [mapping])
|
|
27
|
+
|
|
28
|
+
@easy.perform
|
|
29
|
+
assert_match(/GET/, @easy.body_str)
|
|
30
|
+
|
|
31
|
+
@easy.perform
|
|
32
|
+
assert_match(/GET/, @easy.body_str)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def test_resolve_entries_can_be_objects_that_convert_to_string
|
|
36
|
+
host = "curb-resolve-object.invalid"
|
|
37
|
+
mapping = "#{host}:#{TestServlet.port}:127.0.0.1"
|
|
38
|
+
entry = Object.new
|
|
39
|
+
entry.define_singleton_method(:to_s) { mapping }
|
|
40
|
+
|
|
41
|
+
@easy.url = "http://#{host}:#{TestServlet.port}#{TestServlet.path}"
|
|
42
|
+
@easy.dns_cache_timeout = 0
|
|
43
|
+
@easy.resolve = [entry]
|
|
44
|
+
|
|
45
|
+
@easy.perform
|
|
46
|
+
assert_match(/GET/, @easy.body_str)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
|
2
|
+
|
|
3
|
+
class TestCurbCurlMaxFileSize < Test::Unit::TestCase
|
|
4
|
+
def setup
|
|
5
|
+
@easy = Curl::Easy.new
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def teardown
|
|
9
|
+
Curl.__send__(:clear_safe!) if Curl.respond_to?(:clear_safe!, true)
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_maxfilesize_setopt
|
|
14
|
+
@easy.set(Curl::CURLOPT_MAXFILESIZE, 5000000)
|
|
15
|
+
@easy.set(Curl::CURLOPT_MAXFILESIZE_LARGE, 5000000) if Curl.const_defined?(:CURLOPT_MAXFILESIZE_LARGE)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_max_body_bytes_exact_limit_succeeds
|
|
19
|
+
with_raw_http_response("HTTP/1.1 200 OK\r\nContent-Length: 8\r\n\r\n12345678") do |url|
|
|
20
|
+
@easy.url = url
|
|
21
|
+
@easy.max_body_bytes = 8
|
|
22
|
+
@easy.perform
|
|
23
|
+
|
|
24
|
+
assert_equal '12345678', @easy.body_str
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_max_body_bytes_rejects_large_buffered_response
|
|
29
|
+
with_raw_http_response("HTTP/1.1 200 OK\r\nContent-Length: 64\r\n\r\n#{'x' * 64}") do |url|
|
|
30
|
+
@easy.url = url
|
|
31
|
+
@easy.max_body_bytes = 10
|
|
32
|
+
|
|
33
|
+
assert_body_limit_error do
|
|
34
|
+
@easy.perform
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
assert_operator @easy.body_str.to_s.bytesize, :<=, 10
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_safe_get_accepts_max_body_bytes_as_second_argument
|
|
42
|
+
with_raw_http_response("HTTP/1.1 200 OK\r\nContent-Length: 64\r\n\r\n#{'x' * 64}") do |url|
|
|
43
|
+
assert_body_limit_error do
|
|
44
|
+
Curl.safe_get(url, :max_body_bytes => 10)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def test_safe_get_reapplies_max_body_bytes_after_user_block
|
|
50
|
+
with_raw_http_response("HTTP/1.1 200 OK\r\nContent-Length: 64\r\n\r\n#{'x' * 64}") do |url|
|
|
51
|
+
assert_body_limit_error do
|
|
52
|
+
Curl.safe_get(url, {}, :max_body_bytes => 10) do |easy|
|
|
53
|
+
easy.max_body_bytes = nil
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def test_safe_bang_max_body_bytes_applies_to_easy_perform
|
|
60
|
+
with_raw_http_response("HTTP/1.1 200 OK\r\nContent-Length: 64\r\n\r\n#{'x' * 64}") do |url|
|
|
61
|
+
Curl.safe! do |config|
|
|
62
|
+
config.max_body_bytes = 10
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
@easy.url = url
|
|
66
|
+
|
|
67
|
+
assert_body_limit_error do
|
|
68
|
+
@easy.perform
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def test_safe_bang_reapplies_max_body_bytes_after_shortcut_block
|
|
74
|
+
with_raw_http_response("HTTP/1.1 200 OK\r\nContent-Length: 64\r\n\r\n#{'x' * 64}") do |url|
|
|
75
|
+
Curl.safe! do |config|
|
|
76
|
+
config.max_body_bytes = 10
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
assert_body_limit_error do
|
|
80
|
+
Curl.get(url) do |easy|
|
|
81
|
+
easy.max_body_bytes = nil
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def test_safe_get_max_body_bytes_tightens_global_cap
|
|
88
|
+
with_raw_http_response("HTTP/1.1 200 OK\r\nContent-Length: 64\r\n\r\n#{'x' * 64}") do |url|
|
|
89
|
+
Curl.safe! do |config|
|
|
90
|
+
config.max_body_bytes = 1_000
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
assert_body_limit_error do
|
|
94
|
+
Curl.safe_get(url, :max_body_bytes => 10)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def test_safe_bang_rejects_negative_max_body_bytes
|
|
100
|
+
assert_raise(ArgumentError) do
|
|
101
|
+
Curl.safe! do |config|
|
|
102
|
+
config.max_body_bytes = -1
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def test_safe_head_does_not_apply_body_cap_to_content_length
|
|
108
|
+
with_raw_http_response("HTTP/1.1 200 OK\r\nContent-Length: 65536\r\n\r\n") do |url|
|
|
109
|
+
easy = Curl.safe_head(url, :max_body_bytes => 1)
|
|
110
|
+
|
|
111
|
+
assert_equal 200, easy.response_code
|
|
112
|
+
assert_equal '', easy.body_str
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def test_max_body_bytes_rejects_chunked_response_without_content_length
|
|
117
|
+
chunks = ["1234", "5678", "90"]
|
|
118
|
+
response = +"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"
|
|
119
|
+
chunks.each { |chunk| response << "#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n" }
|
|
120
|
+
response << "0\r\n\r\n"
|
|
121
|
+
|
|
122
|
+
with_raw_http_response(response) do |url|
|
|
123
|
+
@easy.url = url
|
|
124
|
+
@easy.max_body_bytes = 8
|
|
125
|
+
|
|
126
|
+
assert_body_limit_error do
|
|
127
|
+
@easy.perform
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
assert_operator @easy.body_str.to_s.bytesize, :<=, 8
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def test_max_body_bytes_limits_on_body_callback
|
|
135
|
+
chunks = ["1234", "5678", "90"]
|
|
136
|
+
response = +"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"
|
|
137
|
+
chunks.each { |chunk| response << "#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n" }
|
|
138
|
+
response << "0\r\n\r\n"
|
|
139
|
+
seen = +''
|
|
140
|
+
|
|
141
|
+
with_raw_http_response(response) do |url|
|
|
142
|
+
@easy.url = url
|
|
143
|
+
@easy.max_body_bytes = 8
|
|
144
|
+
@easy.on_body { |data| seen << data; data.bytesize }
|
|
145
|
+
|
|
146
|
+
assert_body_limit_error do
|
|
147
|
+
@easy.perform
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
assert_equal '12345678', seen
|
|
151
|
+
assert_nil @easy.body_str
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def test_max_body_bytes_zero_clears_limit
|
|
156
|
+
with_raw_http_response("HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\n123456789012") do |url|
|
|
157
|
+
@easy.url = url
|
|
158
|
+
@easy.max_body_bytes = 1
|
|
159
|
+
@easy.max_body_bytes = 0
|
|
160
|
+
@easy.perform
|
|
161
|
+
|
|
162
|
+
assert_nil @easy.max_body_bytes
|
|
163
|
+
assert_equal '123456789012', @easy.body_str
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def test_max_body_bytes_counter_resets_between_reused_transfers
|
|
168
|
+
@easy.max_body_bytes = 8
|
|
169
|
+
|
|
170
|
+
with_raw_http_response("HTTP/1.1 200 OK\r\nContent-Length: 8\r\n\r\n12345678") do |url|
|
|
171
|
+
@easy.url = url
|
|
172
|
+
@easy.perform
|
|
173
|
+
assert_equal '12345678', @easy.body_str
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
with_raw_http_response("HTTP/1.1 200 OK\r\nContent-Length: 8\r\n\r\nabcdefgh") do |url|
|
|
177
|
+
@easy.url = url
|
|
178
|
+
@easy.perform
|
|
179
|
+
assert_equal 'abcdefgh', @easy.body_str
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
private
|
|
184
|
+
|
|
185
|
+
def assert_body_limit_error
|
|
186
|
+
assert_raise(Curl::Err::FileSizeExceededError) do
|
|
187
|
+
yield
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def with_raw_http_response(response)
|
|
192
|
+
server = TCPServer.new('127.0.0.1', 0)
|
|
193
|
+
port = server.addr[1]
|
|
194
|
+
thread = Thread.new do
|
|
195
|
+
socket = server.accept
|
|
196
|
+
begin
|
|
197
|
+
socket.readpartial(4096)
|
|
198
|
+
rescue EOFError
|
|
199
|
+
end
|
|
200
|
+
socket.write(response)
|
|
201
|
+
socket.close
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
yield "http://127.0.0.1:#{port}/"
|
|
205
|
+
ensure
|
|
206
|
+
server.close if server && !server.closed?
|
|
207
|
+
if thread
|
|
208
|
+
thread.join(5)
|
|
209
|
+
thread.kill if thread.alive?
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|