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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -0
  3. data/README.md +113 -50
  4. data/ext/patron/extconf.rb +55 -20
  5. data/ext/patron/session_ext.c +1092 -761
  6. data/lib/patron/compat.rb +57 -0
  7. data/lib/patron/error.rb +25 -13
  8. data/lib/patron/header_parser.rb +27 -25
  9. data/lib/patron/request.rb +98 -142
  10. data/lib/patron/response.rb +33 -24
  11. data/lib/patron/response_decoding.rb +60 -67
  12. data/lib/patron/session.rb +127 -104
  13. data/lib/patron/util.rb +14 -12
  14. data/lib/patron/version.rb +3 -1
  15. data/lib/patron.rb +9 -15
  16. metadata +12 -49
  17. data/.autotest +0 -15
  18. data/.github/workflows/ci.yml +0 -26
  19. data/.gitignore +0 -10
  20. data/.rspec +0 -0
  21. data/.travis.yml +0 -13
  22. data/.yardopts +0 -1
  23. data/Gemfile +0 -17
  24. data/Rakefile +0 -31
  25. data/ext/patron/.gitignore +0 -4
  26. data/ext/patron/membuffer.c +0 -85
  27. data/ext/patron/membuffer.h +0 -78
  28. data/ext/patron/sglib.h +0 -1952
  29. data/lib/patron/proxy_type.rb +0 -11
  30. data/patron.gemspec +0 -38
  31. data/pic.png +0 -0
  32. data/script/console +0 -11
  33. data/script/test_server +0 -7
  34. data/spec/header_parser_spec.rb +0 -101
  35. data/spec/patron_spec.rb +0 -28
  36. data/spec/request_spec.rb +0 -77
  37. data/spec/response_spec.rb +0 -145
  38. data/spec/sample_response_headers/headers_wetransfer.txt +0 -18
  39. data/spec/sample_response_headers/headers_wetransfer_with_proxy_status.txt +0 -20
  40. data/spec/sample_response_headers/headers_wetransfer_with_redirect.txt +0 -24
  41. data/spec/sample_response_headers/headers_with_set_cookie.txt +0 -9
  42. data/spec/sample_response_headers/sample_http2_header.txt +0 -16
  43. data/spec/sample_response_headers/webmock_headers_without_trailing_crlf.txt +0 -15
  44. data/spec/session_spec.rb +0 -698
  45. data/spec/session_ssl_spec.rb +0 -313
  46. data/spec/spec_helper.rb +0 -34
  47. data/spec/support/certs/cacert.pem +0 -36
  48. data/spec/support/certs/privkey.pem +0 -51
  49. data/spec/support/config.ru +0 -146
  50. data/spec/support/fork.rb +0 -70
  51. data/spec/support/test_server.rb +0 -26
  52. data/spec/util_spec.rb +0 -71
@@ -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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
- 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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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
- pabpxip8zTuPZ6eBPeh4LaFIuWx7wOn7xQ5pfwLbWWCBr+FQbRatkqu3E+L6rhGw
19
- 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
- Zf22SzqylBKSdsrbBfltitMa0YOQSLIMt1kZlOvtK8fb3ZbRf23uX0JLrA/+CgSr
21
- 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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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
- 2Cci1nWwm0/EQxjVTARFCBVtN4asuVLYWpBiJgKxpB8QxTK4CzpIYnebAlrXnLb4
4
- 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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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
- 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
- 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
- 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
- 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
- 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
- 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
- 3gr5NvUvD8ZXzYk2c5YNfeWvsy/gUPbDv+4poy/yNaTYdw4hOwFCnef7Y3H4TIWL
34
- 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
- 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
- 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
- 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
38
- Tmsg4oRHzfquVnr6GK6x7ZHIo5mpHHHdOiyp/UD+anfbbMRItcHkzHDctkaoOKWI
39
- h3P0mYZ5LIJNVuErhucrP57tr+bOOttus9HLHXTYsjOGV4zSKUSVQTOxnTzZepd8
40
- zIdo+wKCAQAg/Z80RPYGd/IVmD0NWxDbRhfEXn37XhRr1eIfNLjpktMGQENSiPEI
41
- FM12S+xSUOC31Hs5u+BNop1kCfd1yuf4NxC8eyMjKO3tM90wc+KUMLeh9TdPZ96J
42
- dD96eVftTuavTkdFZdWB8wSwxDZX3uV4ir1t6bIKDoyz+yqYM3v3HfweJIq0ox2p
43
- TS40cDDWnt/ZIk3TyMS1QPWbr0Jl8or0JYmRVp1m8jiDwcsp9tUd9+/5bgKhC3uM
44
- tY0HjOULzvvHkkul5ADAHyNS7zq9lEwEhIilkhX3M0wX3ZxvXwJPUbgYurcbNmgd
45
- imp6DpuPJPdbg/8bz9YiaAZOnObnE9lFAoIBAGIdAhDDhqhPIW3xDx54TBfxQFi+
46
- CeFw1g2duwXAXkBV98nKeLdTo3tL8gusb+32LzgVIq2spWUN72xXX40NJjW1Bxk5
47
- SGatM1T13BaUFNYtzpM9arDPNr3tCiCSzeVvMKdLfp+Vx9R9arnOgLlGkhRCdEtb
48
- lXAteE7Twuztvad/M0LGpbjN6BD23KLOfxx9C2TgfMuK/Fjt71ASV+80cq4SS2WK
49
- fqZQnKfGIRE8wcY2R5g2AwEzubCRzD93pGG3KleQKxrUKNoV32M2ZZcM04l8woZX
50
- vrkNxM3gbBkhFPAJ9LrmA4YExODUXzWt6Y2mCXuH2Ly60yiLa66HbEfhHrs=
51
- -----END RSA PRIVATE KEY-----
@@ -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
@@ -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