patron 0.13.4 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +97 -0
- data/README.md +113 -50
- data/ext/patron/extconf.rb +55 -20
- data/ext/patron/session_ext.c +1092 -761
- data/lib/patron/compat.rb +57 -0
- data/lib/patron/error.rb +25 -13
- data/lib/patron/header_parser.rb +27 -25
- data/lib/patron/request.rb +98 -142
- data/lib/patron/response.rb +33 -24
- data/lib/patron/response_decoding.rb +60 -67
- data/lib/patron/session.rb +127 -104
- data/lib/patron/util.rb +14 -12
- data/lib/patron/version.rb +3 -1
- data/lib/patron.rb +9 -15
- metadata +12 -49
- data/.autotest +0 -15
- data/.github/workflows/ci.yml +0 -26
- data/.gitignore +0 -10
- data/.rspec +0 -0
- data/.travis.yml +0 -13
- data/.yardopts +0 -1
- data/Gemfile +0 -17
- data/Rakefile +0 -31
- data/ext/patron/.gitignore +0 -4
- data/ext/patron/membuffer.c +0 -85
- data/ext/patron/membuffer.h +0 -78
- data/ext/patron/sglib.h +0 -1952
- data/lib/patron/proxy_type.rb +0 -11
- data/patron.gemspec +0 -38
- data/pic.png +0 -0
- data/script/console +0 -11
- data/script/test_server +0 -7
- data/spec/header_parser_spec.rb +0 -101
- data/spec/patron_spec.rb +0 -28
- data/spec/request_spec.rb +0 -77
- data/spec/response_spec.rb +0 -145
- data/spec/sample_response_headers/headers_wetransfer.txt +0 -18
- data/spec/sample_response_headers/headers_wetransfer_with_proxy_status.txt +0 -20
- data/spec/sample_response_headers/headers_wetransfer_with_redirect.txt +0 -24
- data/spec/sample_response_headers/headers_with_set_cookie.txt +0 -9
- data/spec/sample_response_headers/sample_http2_header.txt +0 -16
- data/spec/sample_response_headers/webmock_headers_without_trailing_crlf.txt +0 -15
- data/spec/session_spec.rb +0 -698
- data/spec/session_ssl_spec.rb +0 -313
- data/spec/spec_helper.rb +0 -34
- data/spec/support/certs/cacert.pem +0 -36
- data/spec/support/certs/privkey.pem +0 -51
- data/spec/support/config.ru +0 -146
- data/spec/support/fork.rb +0 -70
- data/spec/support/test_server.rb +0 -26
- data/spec/util_spec.rb +0 -71
data/spec/session_ssl_spec.rb
DELETED
|
@@ -1,313 +0,0 @@
|
|
|
1
|
-
require File.expand_path("./spec") + '/spec_helper.rb'
|
|
2
|
-
require 'webrick'
|
|
3
|
-
require 'yaml'
|
|
4
|
-
require 'base64'
|
|
5
|
-
require 'fileutils'
|
|
6
|
-
|
|
7
|
-
describe Patron::Session do
|
|
8
|
-
|
|
9
|
-
def yaml_load(str)
|
|
10
|
-
if RUBY_VERSION >= '3.1.0'
|
|
11
|
-
YAML::safe_load(str, permitted_classes: [OpenStruct])
|
|
12
|
-
else
|
|
13
|
-
YAML::load(str)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
before(:each) do
|
|
18
|
-
@session = Patron::Session.new
|
|
19
|
-
@session.base_url = "https://localhost:9043"
|
|
20
|
-
@session.insecure = true
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
it "should retrieve a url with :get" do
|
|
24
|
-
response = @session.get("/test")
|
|
25
|
-
body = yaml_load(response.body)
|
|
26
|
-
expect(body.request_method).to be == "GET"
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
it "should download content with :get and a file path" do
|
|
30
|
-
tmpfile = "/tmp/patron_test.yaml"
|
|
31
|
-
response = @session.get_file "/test", tmpfile
|
|
32
|
-
expect(response.body).to be_nil
|
|
33
|
-
body = yaml_load(File.open(tmpfile).read)
|
|
34
|
-
expect(body.request_method).to be == "GET"
|
|
35
|
-
FileUtils.rm tmpfile
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# See https://github.com/curl/curl/issues/788
|
|
39
|
-
# Basically any HTTPS operation crashes on OSX with securetransport-enabled libCURL
|
|
40
|
-
it "should download content in a forked subprocess" do
|
|
41
|
-
# To trigger the bug, we need to perform a request in the master process first
|
|
42
|
-
tmpfile = "/tmp/patron_test.yaml"
|
|
43
|
-
@session.get_file "/test", tmpfile
|
|
44
|
-
FileUtils.rm tmpfile
|
|
45
|
-
|
|
46
|
-
# and this one segfaults
|
|
47
|
-
pid = fork do
|
|
48
|
-
response = @session.get_file "/test", tmpfile
|
|
49
|
-
expect(response.body).to be_nil
|
|
50
|
-
body = yaml_load(File.open(tmpfile).read)
|
|
51
|
-
expect(body.request_method).to be == "GET"
|
|
52
|
-
FileUtils.rm tmpfile
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
exit_pid, status = Process.wait2(pid)
|
|
56
|
-
expect(status.exitstatus).to be_zero
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
it "should download correctly(md5 ok) with get_file" do
|
|
60
|
-
tmpfile = "/tmp/picture"
|
|
61
|
-
response = @session.get_file "/picture", tmpfile
|
|
62
|
-
expect(response.body).to be_nil
|
|
63
|
-
expect(File.size(File.join(File.dirname(__FILE__),"../pic.png"))).to be == File.size(tmpfile)
|
|
64
|
-
FileUtils.rm tmpfile
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
it "should include custom headers in a request" do
|
|
68
|
-
response = @session.get("/test", {"User-Agent" => "PatronTest"})
|
|
69
|
-
body = yaml_load(response.body)
|
|
70
|
-
expect(body.header["user-agent"]).to be == ["PatronTest"]
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
it "should merge custom headers with session headers" do
|
|
74
|
-
@session.headers["X-Test"] = "Testing"
|
|
75
|
-
response = @session.get("/test", {"User-Agent" => "PatronTest"})
|
|
76
|
-
body = yaml_load(response.body)
|
|
77
|
-
expect(body.header["user-agent"]).to be == ["PatronTest"]
|
|
78
|
-
expect(body.header["x-test"]).to be == ["Testing"]
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
it "should raise an exception on timeout" do
|
|
82
|
-
@session.timeout = 1
|
|
83
|
-
expect {
|
|
84
|
-
@session.get("/timeout?millis=1100")
|
|
85
|
-
}.to raise_error(Patron::TimeoutError)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
it "should follow redirects by default" do
|
|
89
|
-
@session.max_redirects = 1
|
|
90
|
-
response = @session.get("/redirect")
|
|
91
|
-
body = yaml_load(response.body)
|
|
92
|
-
expect(response.status).to be == 200
|
|
93
|
-
expect(body.path).to be == "/test"
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
it "should include redirect count in response" do
|
|
97
|
-
@session.max_redirects = 1
|
|
98
|
-
response = @session.get("/redirect")
|
|
99
|
-
expect(response.redirect_count).to be == 1
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
it "should not follow redirects when configured to do so" do
|
|
103
|
-
@session.max_redirects = 0
|
|
104
|
-
response = @session.get("/redirect")
|
|
105
|
-
expect(response.status).to be == 301
|
|
106
|
-
expect(response.body).to be_empty
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
it "should retrieve URL metadata with :head" do
|
|
110
|
-
response = @session.head("/test")
|
|
111
|
-
expect(response.status).to be == 200
|
|
112
|
-
expect(response.body).to be_empty
|
|
113
|
-
expect(response.headers).to_not be_empty
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
it "should send a delete request with :delete" do
|
|
117
|
-
response = @session.delete("/test")
|
|
118
|
-
body = yaml_load(response.body)
|
|
119
|
-
expect(body.request_method).to be == "DELETE"
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
it "should send a COPY request with :copy" do
|
|
123
|
-
response = @session.copy("/test", "/test2")
|
|
124
|
-
body = yaml_load(response.body)
|
|
125
|
-
expect(body.request_method).to be == "COPY"
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
it "should include a Destination header in COPY requests" do
|
|
129
|
-
response = @session.copy("/test", "/test2")
|
|
130
|
-
body = yaml_load(response.body)
|
|
131
|
-
expect(body.header['destination'].first).to be == "/test2"
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
it "should upload data with :get" do
|
|
135
|
-
data = "upload data"
|
|
136
|
-
response = @session.request(:get, "/test", {}, :data => data)
|
|
137
|
-
body = yaml_load(response.body)
|
|
138
|
-
expect(body.request_method).to be == "GET"
|
|
139
|
-
expect(body.header['content-length']).to be == [data.size.to_s]
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
it "should upload data with :put" do
|
|
143
|
-
data = "upload data"
|
|
144
|
-
response = @session.put("/test", data)
|
|
145
|
-
body = yaml_load(response.body)
|
|
146
|
-
expect(body.request_method).to be == "PUT"
|
|
147
|
-
expect(body.header['content-length']).to be == [data.size.to_s]
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
it "should raise when no data is provided to :put" do
|
|
151
|
-
expect { @session.put("/test", nil) }.to raise_error(ArgumentError)
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
it "should upload a file with :put" do
|
|
155
|
-
response = @session.put_file("/test", "LICENSE")
|
|
156
|
-
body = yaml_load(response.body)
|
|
157
|
-
expect(body.request_method).to be == "PUT"
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
it "should raise when no file is provided to :put" do
|
|
161
|
-
expect { @session.put_file("/test", nil) }.to raise_error(ArgumentError)
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
it "should use chunked encoding when uploading a file with :put" do
|
|
165
|
-
response = @session.put_file("/test", "LICENSE")
|
|
166
|
-
body = yaml_load(response.body)
|
|
167
|
-
expect(body.header['transfer-encoding'].first).to be == "chunked"
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
it "should upload data with :post" do
|
|
171
|
-
data = "upload data"
|
|
172
|
-
response = @session.post("/test", data)
|
|
173
|
-
body = yaml_load(response.body)
|
|
174
|
-
expect(body.request_method).to be == "POST"
|
|
175
|
-
expect(body.header['content-length']).to be == [data.size.to_s]
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
it "should post a hash of arguments as a urlencoded form" do
|
|
179
|
-
data = {:foo => 123, 'baz' => '++hello world++'}
|
|
180
|
-
response = @session.post("/testpost", data)
|
|
181
|
-
body = yaml_load(response.body)
|
|
182
|
-
expect(body['content_type']).to be == "application/x-www-form-urlencoded"
|
|
183
|
-
expect(body['body']).to match(/baz=%2B%2Bhello%20world%2B%2B/)
|
|
184
|
-
expect(body['body']).to match(/foo=123/)
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
it "should raise when no data is provided to :post" do
|
|
188
|
-
expect { @session.post("/test", nil) }.to raise_error(ArgumentError)
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
it "should upload a file with :post" do
|
|
192
|
-
response = @session.post_file("/test", "LICENSE")
|
|
193
|
-
body = yaml_load(response.body)
|
|
194
|
-
expect(body.request_method).to be == "POST"
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
it "should upload a multipart with :post" do
|
|
198
|
-
response = @session.post_multipart("/test", { :test_data => "123" }, { :test_file => "LICENSE" } )
|
|
199
|
-
body = yaml_load(response.body)
|
|
200
|
-
expect(body.request_method).to be == "POST"
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
it "should raise when no file is provided to :post" do
|
|
204
|
-
expect { @session.post_file("/test", nil) }.to raise_error(ArgumentError)
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
it "should use chunked encoding when uploading a file with :post" do
|
|
208
|
-
response = @session.post_file("/test", "LICENSE")
|
|
209
|
-
body = yaml_load(response.body)
|
|
210
|
-
expect(body.header['transfer-encoding'].first).to be == "chunked"
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
it "should handle cookies if set" do
|
|
214
|
-
@session.handle_cookies
|
|
215
|
-
response = @session.get("/setcookie").body
|
|
216
|
-
expect(yaml_load(response).header['cookie'].first).to be == "session_id=foo123"
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
it "should not handle cookies by default" do
|
|
220
|
-
response = @session.get("/setcookie").body
|
|
221
|
-
expect(yaml_load(response).header).to_not include('cookie')
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
it "should raise exception if cookie store is not writable or readable" do
|
|
225
|
-
expect { @session.handle_cookies("/trash/clash/foo") }.to raise_error(ArgumentError)
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
it "should work with multiple threads" do
|
|
229
|
-
threads = []
|
|
230
|
-
3.times do
|
|
231
|
-
threads << Thread.new do
|
|
232
|
-
session = Patron::Session.new
|
|
233
|
-
session.base_url = "https://localhost:9043"
|
|
234
|
-
session.insecure = true
|
|
235
|
-
session.post_file("/test", "LICENSE")
|
|
236
|
-
end
|
|
237
|
-
end
|
|
238
|
-
threads.each {|t| t.join }
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
it "should fail when insecure mode is off" do
|
|
242
|
-
expect {
|
|
243
|
-
@session.insecure = nil
|
|
244
|
-
response = @session.get("/test")
|
|
245
|
-
}.to raise_error(Patron::Error)
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
it "should work when insecure mode is off but certificate is supplied" do
|
|
249
|
-
@session.insecure = nil
|
|
250
|
-
@session.cacert = File.join(__dir__, 'support', 'certs', 'cacert.pem')
|
|
251
|
-
response = @session.get("/test")
|
|
252
|
-
body = yaml_load(response.body)
|
|
253
|
-
expect(body.request_method).to be == "GET"
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
it "should allow to specify insecure mode per-request" do
|
|
257
|
-
@session.insecure = false
|
|
258
|
-
expect {
|
|
259
|
-
@session.request(:get, "/test", {}, insecure: true)
|
|
260
|
-
}.not_to raise_error
|
|
261
|
-
expect {
|
|
262
|
-
@session.request(:get, "/test", {})
|
|
263
|
-
}.to raise_error(Patron::Error)
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
it "should work with different SSL versions" do
|
|
267
|
-
['TLSv1_0','TLSv1_1'].each do |version|
|
|
268
|
-
@session.ssl_version = version
|
|
269
|
-
response = @session.get("/test")
|
|
270
|
-
expect(response.status).to be == 200
|
|
271
|
-
end
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
it "should raise when an unsupported or unknown SSL version is requested" do
|
|
275
|
-
['something', 1].each do |version|
|
|
276
|
-
@session.ssl_version = version
|
|
277
|
-
expect {
|
|
278
|
-
@session.get("/test")
|
|
279
|
-
}.to raise_error(Patron::UnsupportedSSLVersion)
|
|
280
|
-
end
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
it "should work with different HTTP versions" do
|
|
284
|
-
['HTTPv1_0','HTTPv1_1'].each do |version|
|
|
285
|
-
@session.http_version = version
|
|
286
|
-
response = @session.get("/test")
|
|
287
|
-
expect(response.status).to be == 200
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
it "should raise when an unsupported or unknown HTTP version is requested" do
|
|
292
|
-
['something', 1].each do |version|
|
|
293
|
-
@session.http_version = version
|
|
294
|
-
expect {
|
|
295
|
-
@session.get("/test")
|
|
296
|
-
}.to raise_error(Patron::UnsupportedHTTPVersion)
|
|
297
|
-
end
|
|
298
|
-
end
|
|
299
|
-
|
|
300
|
-
# ------------------------------------------------------------------------
|
|
301
|
-
describe 'when debug is enabled' do
|
|
302
|
-
it 'it should not clobber stderr' do
|
|
303
|
-
rdev = STDERR.stat.rdev
|
|
304
|
-
|
|
305
|
-
@session.enable_debug
|
|
306
|
-
expect(STDERR.stat.rdev).to be == rdev
|
|
307
|
-
|
|
308
|
-
@session.enable_debug
|
|
309
|
-
expect(STDERR.stat.rdev).to be == rdev
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
end
|
data/spec/spec_helper.rb
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
if ENV["COVERAGE"]
|
|
2
|
-
require 'simplecov'
|
|
3
|
-
SimpleCov.start do
|
|
4
|
-
add_filter "/spec/"
|
|
5
|
-
end
|
|
6
|
-
end
|
|
7
|
-
require 'rspec'
|
|
8
|
-
|
|
9
|
-
# Kill warnings that not raising a specific exception still allows the method
|
|
10
|
-
# to fail with another exception
|
|
11
|
-
RSpec::Expectations.configuration.warn_about_potential_false_positives = false
|
|
12
|
-
|
|
13
|
-
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
|
14
|
-
$:.unshift(File.dirname(__FILE__) + '/../ext')
|
|
15
|
-
require 'patron'
|
|
16
|
-
|
|
17
|
-
$stderr.puts "Build against #{Patron.libcurl_version}"
|
|
18
|
-
|
|
19
|
-
Dir['./spec/support/**/*.rb'].each { |fn| require fn }
|
|
20
|
-
|
|
21
|
-
http_server = Fork.new { PatronTestServer.start(false, 9001) }
|
|
22
|
-
|
|
23
|
-
sleep 0.1 # Don't interfere the start up output of two processes.
|
|
24
|
-
|
|
25
|
-
https_server = Fork.new { PatronTestServer.start(true, 9043) }
|
|
26
|
-
|
|
27
|
-
RSpec.configure do |c|
|
|
28
|
-
c.after(:suite) do
|
|
29
|
-
http_server.kill("TERM")
|
|
30
|
-
https_server.kill("TERM")
|
|
31
|
-
http_server.wait
|
|
32
|
-
https_server.wait
|
|
33
|
-
end
|
|
34
|
-
end
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
-----BEGIN CERTIFICATE-----
|
|
2
|
-
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
-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
-
d24xIDAeBgNVBAoMF1BhdHJvbiBUZXN0IENlcnRpZmljYXRlMSAwHgYDVQQLDBdQ
|
|
5
|
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-
pabpxip8zTuPZ6eBPeh4LaFIuWx7wOn7xQ5pfwLbWWCBr+FQbRatkqu3E+L6rhGw
|
|
19
|
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
|
|
35
|
-
djS6lZ9vTEbRM+GhU2PMKfvJbiQ/Y6Q=
|
|
36
|
-
-----END CERTIFICATE-----
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
-----BEGIN RSA PRIVATE KEY-----
|
|
2
|
-
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
-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
-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
-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
-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
-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
-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
-
ga/hUG0WrZKrtxPi+q4RsL/2v45VZzXpJEpQA7Mr8mu7eIan7AwMQeav7PzKVyLa
|
|
10
|
-
xmH9bILWV9J5zZD5IKxdvGX9tks6spQSknbK2wX5bYrTGtGDkEiyDLdZGZTr7SvH
|
|
11
|
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-
Dbv87Jke4aZtKioI7sASLA/z42jlVQmeEfPtvoQlewKCAQEApgdpxsfcQ2VWkp5z
|
|
35
|
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
-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
|
|
51
|
-
-----END RSA PRIVATE KEY-----
|
data/spec/support/config.ru
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
require 'yaml'
|
|
2
|
-
require 'ostruct'
|
|
3
|
-
require 'zlib'
|
|
4
|
-
|
|
5
|
-
## HTTP test server for integration tests
|
|
6
|
-
|
|
7
|
-
Readback = Proc.new {|env|
|
|
8
|
-
# The Patron test suite is originally written to enable the following
|
|
9
|
-
# testing pattern:
|
|
10
|
-
# * Patron does a request
|
|
11
|
-
# * The request gets captured by Webrick
|
|
12
|
-
# * Webrick then takes it's Request object and YAMLs it wholesale (body, headers and all)
|
|
13
|
-
# * ...and sends it back to the client
|
|
14
|
-
# * The test suite then de-YAMLs the request object from the response body and does assertions on it
|
|
15
|
-
#
|
|
16
|
-
# The easiest way to fake it, preserving the entire test suite intact, is to simulate a Webrick
|
|
17
|
-
# request object using an ostruct. Of note is the following:
|
|
18
|
-
#
|
|
19
|
-
# 1) Webrick returns headers in arrays by default, accounting for repeats like with Cookie
|
|
20
|
-
# 2) Webrick does not convert headers to ENV_VARS_FOR_FCI it only downcases them. We have to match that.
|
|
21
|
-
req = Rack::Request.new(env)
|
|
22
|
-
req_headers = env.to_a.select do |(k,v)|
|
|
23
|
-
k.is_a?(String) && v.is_a?(String)
|
|
24
|
-
end.map do |(k,v)|
|
|
25
|
-
[k.downcase.gsub(/^http_/, '').gsub(/_/o, '-'), [v]]
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
fake_webrick_request_object = OpenStruct.new({
|
|
29
|
-
:fullpath => req.fullpath,
|
|
30
|
-
:path => req.path,
|
|
31
|
-
:query_string => req.query_string,
|
|
32
|
-
:request_method => req.request_method.to_s,
|
|
33
|
-
:header => Hash[req_headers],
|
|
34
|
-
:body => env['rack.input'].read,
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
body_str = fake_webrick_request_object.to_yaml
|
|
38
|
-
[200, {'Content-Type' => 'text/plain', 'Content-Length' => body_str.bytesize.to_s}, [body_str]]
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
GzipServlet = Proc.new {|env|
|
|
42
|
-
raise "Need to have the right Accept-Encoding: header" unless env['HTTP_ACCEPT_ENCODING']
|
|
43
|
-
|
|
44
|
-
body = []
|
|
45
|
-
content_length = 0
|
|
46
|
-
z = Zlib::Deflate.new(Zlib::DEFAULT_COMPRESSION)
|
|
47
|
-
1024.times do
|
|
48
|
-
chunk = z.deflate('Some highly compressible data')
|
|
49
|
-
content_length += chunk.bytesize
|
|
50
|
-
body << chunk
|
|
51
|
-
end
|
|
52
|
-
fin = z.finish.to_s
|
|
53
|
-
body << fin
|
|
54
|
-
content_length += fin.bytesize
|
|
55
|
-
z.close
|
|
56
|
-
|
|
57
|
-
[200, {'Content-Encoding' => 'deflate', 'Content-Length' => content_length.to_s, 'Vary' => 'Accept-Encoding'}, body]
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
TimeoutServlet = Proc.new {|env|
|
|
61
|
-
query_vars = Rack::Utils.parse_nested_query(env.fetch('QUERY_STRING'))
|
|
62
|
-
query_millis = query_vars.fetch('millis').to_i
|
|
63
|
-
sleep(query_millis / 1000.0)
|
|
64
|
-
[200, {'Content-Type' => 'text/plain'}, ['That took a while']]
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
SlowServlet = Proc.new {|env|
|
|
68
|
-
body = Enumerator.new do |y|
|
|
69
|
-
y.yield 'x'
|
|
70
|
-
sleep 5
|
|
71
|
-
y.yield 'rest of body'
|
|
72
|
-
end
|
|
73
|
-
[200, {'Content-Type' => 'text/plain'}, body]
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
RedirectServlet = Proc.new {|env|
|
|
77
|
-
url_scheme = env.fetch('rack.url_scheme')
|
|
78
|
-
port = env.fetch('SERVER_PORT')
|
|
79
|
-
[301, {'Location' => "#{url_scheme}://localhost:#{port}/test"}, []]
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
EvilRedirectServlet = Proc.new {|env|
|
|
83
|
-
[301, {'Location' => "smtp://mailbox:secret@localhost"}, []]
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
BodyReadback = Proc.new {|env|
|
|
87
|
-
readback = {'method' => env['REQUEST_METHOD'], 'body' => env['rack.input'].read, 'content_type' => env.fetch('CONTENT_TYPE')}
|
|
88
|
-
[200, {'Content-Type' => 'text/plain'}, [OpenStruct.new(readback).to_yaml]]
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
TestPatchBodyServlet = BodyReadback
|
|
92
|
-
|
|
93
|
-
SetCookieServlet = Proc.new {|env|
|
|
94
|
-
[301, {'Set-Cookie' => 'session_id=foo123', 'Location' => 'http://localhost:9001/test'}, []]
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
RepetitiveHeaderServlet = Proc.new {|env|
|
|
98
|
-
# The values of the header must be Strings,
|
|
99
|
-
# consisting of lines (for multiple header values, e.g. multiple
|
|
100
|
-
# <tt>Set-Cookie</tt> values) separated by "\\n".
|
|
101
|
-
[200, {'Set-Cookie' => "a=1\nb=2", 'Content-Type' => 'text/plain'}, ['Hi.']]
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
PictureServlet = Proc.new {|env|
|
|
105
|
-
# Rack::File allows us to test Range support as well
|
|
106
|
-
env_with_adjusted_path = env.merge('PATH_INFO' => Rack::Utils.escape('/pic.png'))
|
|
107
|
-
Rack::File.new('./').call(env_with_adjusted_path)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
RedirectToPictureServlet = Proc.new {|env|
|
|
111
|
-
[307, {'Location' => '/picture'}, []]
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
WrongContentLengthServlet = Proc.new {|env|
|
|
115
|
-
[200, {'Content-Length' => '1024', 'Content-Type' => 'text/plain'}, ['Hello.']]
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
# Serves a substantial amount of data
|
|
119
|
-
LargeServlet = Proc.new {|env|
|
|
120
|
-
rng = Random.new
|
|
121
|
-
len = 15 * 1024 * 1024
|
|
122
|
-
body = Enumerator.new do |y|
|
|
123
|
-
15.times do
|
|
124
|
-
y.yield(rng.bytes(1024 * 1024))
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
|
-
[200, {'Content-Type' => 'binary/octet-stream', 'Content-Length' => len.to_s}, body]
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
run Rack::URLMap.new({
|
|
131
|
-
"/" => Proc.new {|env| [200, {'Content-Length' => '2'}, ['Welcome']]},
|
|
132
|
-
"/test" => Readback,
|
|
133
|
-
"/testpost" => BodyReadback,
|
|
134
|
-
"/testpatch" => BodyReadback,
|
|
135
|
-
"/timeout" => TimeoutServlet,
|
|
136
|
-
"/slow" => SlowServlet,
|
|
137
|
-
"/redirect" => RedirectServlet,
|
|
138
|
-
"/evil-redirect" => EvilRedirectServlet,
|
|
139
|
-
"/picture" => PictureServlet,
|
|
140
|
-
"/redirect-to-picture" => RedirectToPictureServlet,
|
|
141
|
-
"/very-large" => LargeServlet,
|
|
142
|
-
"/setcookie" => SetCookieServlet,
|
|
143
|
-
"/repetitiveheader" => RepetitiveHeaderServlet,
|
|
144
|
-
"/wrongcontentlength" => WrongContentLengthServlet,
|
|
145
|
-
"/gzip-compressed" => GzipServlet,
|
|
146
|
-
})
|
data/spec/support/fork.rb
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
require 'thread'
|
|
2
|
-
|
|
3
|
-
class Fork
|
|
4
|
-
def initialize(&block)
|
|
5
|
-
@mu = Mutex.new
|
|
6
|
-
@cond = ConditionVariable.new
|
|
7
|
-
@pstate = nil
|
|
8
|
-
@pid = Process.fork(&block)
|
|
9
|
-
@killed = false
|
|
10
|
-
|
|
11
|
-
# Start monitoring the PID.
|
|
12
|
-
Thread.new { monitor }
|
|
13
|
-
|
|
14
|
-
# Kill the process anyway when the program exits.
|
|
15
|
-
ppid = Process.pid
|
|
16
|
-
at_exit do
|
|
17
|
-
if ppid == Process.pid # Make sure we are not inside another fork spawned by rspec example.
|
|
18
|
-
do_kill("KILL")
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# Wait for process to exit.
|
|
24
|
-
def wait(timeout = nil)
|
|
25
|
-
@mu.synchronize do
|
|
26
|
-
next @pstate unless @pstate.nil?
|
|
27
|
-
|
|
28
|
-
@cond.wait(@mu, timeout)
|
|
29
|
-
@pstate
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Signal the process.
|
|
34
|
-
def kill(sig)
|
|
35
|
-
already_killed = @mu.synchronize do
|
|
36
|
-
old = @killed
|
|
37
|
-
@killed = true
|
|
38
|
-
old
|
|
39
|
-
end
|
|
40
|
-
signaled = do_kill(sig)
|
|
41
|
-
Thread.new { reaper } if signaled && !already_killed
|
|
42
|
-
signaled
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
private
|
|
46
|
-
|
|
47
|
-
# Signal the process.
|
|
48
|
-
def do_kill(sig)
|
|
49
|
-
Process.kill(sig, @pid)
|
|
50
|
-
true
|
|
51
|
-
rescue Errno::ESRCH # No such process
|
|
52
|
-
false
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Monitor the process state.
|
|
56
|
-
def monitor
|
|
57
|
-
_, pstate = Process.wait2(@pid)
|
|
58
|
-
|
|
59
|
-
@mu.synchronize do
|
|
60
|
-
@pstate = pstate
|
|
61
|
-
@cond.broadcast
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
# Wait 500 milliseconds and force terminate.
|
|
66
|
-
def reaper
|
|
67
|
-
pstate = wait(0.5)
|
|
68
|
-
do_kill("KILL") unless pstate
|
|
69
|
-
end
|
|
70
|
-
end
|
data/spec/support/test_server.rb
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
require 'rack'
|
|
2
|
-
require 'puma'
|
|
3
|
-
require 'rack/handler/puma'
|
|
4
|
-
|
|
5
|
-
class PatronTestServer
|
|
6
|
-
APP = Rack::Builder.new { eval(File.read(File.join(__dir__, 'config.ru'))) }
|
|
7
|
-
|
|
8
|
-
def self.start(ssl = false, port = 9001 )
|
|
9
|
-
# Reset the RSpec's SIGINT handler that does not really terminate after
|
|
10
|
-
# the first Ctrl+C pressed.
|
|
11
|
-
# Useful to terminate the forked process before Puma is actually started:
|
|
12
|
-
# it happens when running one particular example that does not need Puma
|
|
13
|
-
# so the specs are in fact finished before the Puma started.
|
|
14
|
-
Signal.trap('INT', 'EXIT')
|
|
15
|
-
@ssl = ssl
|
|
16
|
-
keypath = File.join(__dir__, 'certs', 'privkey.pem')
|
|
17
|
-
certpath = File.join(__dir__, 'certs', 'cacert.pem')
|
|
18
|
-
|
|
19
|
-
host = if ssl
|
|
20
|
-
'ssl://0.0.0.0:%d?key=%s&cert=%s' % [port, keypath, certpath]
|
|
21
|
-
else
|
|
22
|
-
'0.0.0.0'
|
|
23
|
-
end
|
|
24
|
-
Rack::Handler::Puma.run(APP, {:Port => port.to_i, :Verbose => true, :Host => host})
|
|
25
|
-
end
|
|
26
|
-
end
|