patron 0.13.1 → 0.13.4
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 +5 -5
- data/.github/workflows/ci.yml +26 -0
- data/.travis.yml +10 -11
- data/CHANGELOG.md +21 -1
- data/Gemfile +14 -1
- data/README.md +92 -50
- data/ext/patron/extconf.rb +3 -4
- data/ext/patron/session_ext.c +111 -138
- data/lib/patron/request.rb +2 -2
- data/lib/patron/session.rb +2 -4
- data/lib/patron/version.rb +1 -1
- data/patron.gemspec +6 -14
- data/spec/patron_spec.rb +1 -1
- data/spec/session_spec.rb +119 -68
- data/spec/session_ssl_spec.rb +43 -40
- data/spec/spec_helper.rb +14 -2
- data/spec/support/config.ru +31 -15
- data/spec/support/fork.rb +70 -0
- data/spec/support/test_server.rb +12 -6
- metadata +13 -125
- /data/spec/{certs → support/certs}/cacert.pem +0 -0
- /data/spec/{certs → support/certs}/privkey.pem +0 -0
data/spec/session_ssl_spec.rb
CHANGED
@@ -6,6 +6,14 @@ require 'fileutils'
|
|
6
6
|
|
7
7
|
describe Patron::Session do
|
8
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
|
+
|
9
17
|
before(:each) do
|
10
18
|
@session = Patron::Session.new
|
11
19
|
@session.base_url = "https://localhost:9043"
|
@@ -14,7 +22,7 @@ describe Patron::Session do
|
|
14
22
|
|
15
23
|
it "should retrieve a url with :get" do
|
16
24
|
response = @session.get("/test")
|
17
|
-
body =
|
25
|
+
body = yaml_load(response.body)
|
18
26
|
expect(body.request_method).to be == "GET"
|
19
27
|
end
|
20
28
|
|
@@ -22,7 +30,7 @@ describe Patron::Session do
|
|
22
30
|
tmpfile = "/tmp/patron_test.yaml"
|
23
31
|
response = @session.get_file "/test", tmpfile
|
24
32
|
expect(response.body).to be_nil
|
25
|
-
body =
|
33
|
+
body = yaml_load(File.open(tmpfile).read)
|
26
34
|
expect(body.request_method).to be == "GET"
|
27
35
|
FileUtils.rm tmpfile
|
28
36
|
end
|
@@ -32,15 +40,14 @@ describe Patron::Session do
|
|
32
40
|
it "should download content in a forked subprocess" do
|
33
41
|
# To trigger the bug, we need to perform a request in the master process first
|
34
42
|
tmpfile = "/tmp/patron_test.yaml"
|
35
|
-
@session.get_file "/
|
36
|
-
|
43
|
+
@session.get_file "/test", tmpfile
|
44
|
+
FileUtils.rm tmpfile
|
37
45
|
|
38
46
|
# and this one segfaults
|
39
47
|
pid = fork do
|
40
|
-
tmpfile = "/tmp/patron_test.yaml"
|
41
48
|
response = @session.get_file "/test", tmpfile
|
42
49
|
expect(response.body).to be_nil
|
43
|
-
body =
|
50
|
+
body = yaml_load(File.open(tmpfile).read)
|
44
51
|
expect(body.request_method).to be == "GET"
|
45
52
|
FileUtils.rm tmpfile
|
46
53
|
end
|
@@ -59,14 +66,14 @@ describe Patron::Session do
|
|
59
66
|
|
60
67
|
it "should include custom headers in a request" do
|
61
68
|
response = @session.get("/test", {"User-Agent" => "PatronTest"})
|
62
|
-
body =
|
69
|
+
body = yaml_load(response.body)
|
63
70
|
expect(body.header["user-agent"]).to be == ["PatronTest"]
|
64
71
|
end
|
65
72
|
|
66
73
|
it "should merge custom headers with session headers" do
|
67
74
|
@session.headers["X-Test"] = "Testing"
|
68
75
|
response = @session.get("/test", {"User-Agent" => "PatronTest"})
|
69
|
-
body =
|
76
|
+
body = yaml_load(response.body)
|
70
77
|
expect(body.header["user-agent"]).to be == ["PatronTest"]
|
71
78
|
expect(body.header["x-test"]).to be == ["Testing"]
|
72
79
|
end
|
@@ -81,7 +88,7 @@ describe Patron::Session do
|
|
81
88
|
it "should follow redirects by default" do
|
82
89
|
@session.max_redirects = 1
|
83
90
|
response = @session.get("/redirect")
|
84
|
-
body =
|
91
|
+
body = yaml_load(response.body)
|
85
92
|
expect(response.status).to be == 200
|
86
93
|
expect(body.path).to be == "/test"
|
87
94
|
end
|
@@ -108,26 +115,26 @@ describe Patron::Session do
|
|
108
115
|
|
109
116
|
it "should send a delete request with :delete" do
|
110
117
|
response = @session.delete("/test")
|
111
|
-
body =
|
118
|
+
body = yaml_load(response.body)
|
112
119
|
expect(body.request_method).to be == "DELETE"
|
113
120
|
end
|
114
121
|
|
115
122
|
it "should send a COPY request with :copy" do
|
116
123
|
response = @session.copy("/test", "/test2")
|
117
|
-
body =
|
124
|
+
body = yaml_load(response.body)
|
118
125
|
expect(body.request_method).to be == "COPY"
|
119
126
|
end
|
120
127
|
|
121
128
|
it "should include a Destination header in COPY requests" do
|
122
129
|
response = @session.copy("/test", "/test2")
|
123
|
-
body =
|
130
|
+
body = yaml_load(response.body)
|
124
131
|
expect(body.header['destination'].first).to be == "/test2"
|
125
132
|
end
|
126
133
|
|
127
134
|
it "should upload data with :get" do
|
128
135
|
data = "upload data"
|
129
136
|
response = @session.request(:get, "/test", {}, :data => data)
|
130
|
-
body =
|
137
|
+
body = yaml_load(response.body)
|
131
138
|
expect(body.request_method).to be == "GET"
|
132
139
|
expect(body.header['content-length']).to be == [data.size.to_s]
|
133
140
|
end
|
@@ -135,7 +142,7 @@ describe Patron::Session do
|
|
135
142
|
it "should upload data with :put" do
|
136
143
|
data = "upload data"
|
137
144
|
response = @session.put("/test", data)
|
138
|
-
body =
|
145
|
+
body = yaml_load(response.body)
|
139
146
|
expect(body.request_method).to be == "PUT"
|
140
147
|
expect(body.header['content-length']).to be == [data.size.to_s]
|
141
148
|
end
|
@@ -146,7 +153,7 @@ describe Patron::Session do
|
|
146
153
|
|
147
154
|
it "should upload a file with :put" do
|
148
155
|
response = @session.put_file("/test", "LICENSE")
|
149
|
-
body =
|
156
|
+
body = yaml_load(response.body)
|
150
157
|
expect(body.request_method).to be == "PUT"
|
151
158
|
end
|
152
159
|
|
@@ -156,14 +163,14 @@ describe Patron::Session do
|
|
156
163
|
|
157
164
|
it "should use chunked encoding when uploading a file with :put" do
|
158
165
|
response = @session.put_file("/test", "LICENSE")
|
159
|
-
body =
|
166
|
+
body = yaml_load(response.body)
|
160
167
|
expect(body.header['transfer-encoding'].first).to be == "chunked"
|
161
168
|
end
|
162
169
|
|
163
170
|
it "should upload data with :post" do
|
164
171
|
data = "upload data"
|
165
172
|
response = @session.post("/test", data)
|
166
|
-
body =
|
173
|
+
body = yaml_load(response.body)
|
167
174
|
expect(body.request_method).to be == "POST"
|
168
175
|
expect(body.header['content-length']).to be == [data.size.to_s]
|
169
176
|
end
|
@@ -171,7 +178,7 @@ describe Patron::Session do
|
|
171
178
|
it "should post a hash of arguments as a urlencoded form" do
|
172
179
|
data = {:foo => 123, 'baz' => '++hello world++'}
|
173
180
|
response = @session.post("/testpost", data)
|
174
|
-
body =
|
181
|
+
body = yaml_load(response.body)
|
175
182
|
expect(body['content_type']).to be == "application/x-www-form-urlencoded"
|
176
183
|
expect(body['body']).to match(/baz=%2B%2Bhello%20world%2B%2B/)
|
177
184
|
expect(body['body']).to match(/foo=123/)
|
@@ -183,13 +190,13 @@ describe Patron::Session do
|
|
183
190
|
|
184
191
|
it "should upload a file with :post" do
|
185
192
|
response = @session.post_file("/test", "LICENSE")
|
186
|
-
body =
|
193
|
+
body = yaml_load(response.body)
|
187
194
|
expect(body.request_method).to be == "POST"
|
188
195
|
end
|
189
196
|
|
190
197
|
it "should upload a multipart with :post" do
|
191
198
|
response = @session.post_multipart("/test", { :test_data => "123" }, { :test_file => "LICENSE" } )
|
192
|
-
body =
|
199
|
+
body = yaml_load(response.body)
|
193
200
|
expect(body.request_method).to be == "POST"
|
194
201
|
end
|
195
202
|
|
@@ -199,33 +206,19 @@ describe Patron::Session do
|
|
199
206
|
|
200
207
|
it "should use chunked encoding when uploading a file with :post" do
|
201
208
|
response = @session.post_file("/test", "LICENSE")
|
202
|
-
body =
|
209
|
+
body = yaml_load(response.body)
|
203
210
|
expect(body.header['transfer-encoding'].first).to be == "chunked"
|
204
211
|
end
|
205
212
|
|
206
213
|
it "should handle cookies if set" do
|
207
214
|
@session.handle_cookies
|
208
215
|
response = @session.get("/setcookie").body
|
209
|
-
expect(
|
216
|
+
expect(yaml_load(response).header['cookie'].first).to be == "session_id=foo123"
|
210
217
|
end
|
211
218
|
|
212
219
|
it "should not handle cookies by default" do
|
213
220
|
response = @session.get("/setcookie").body
|
214
|
-
expect(
|
215
|
-
end
|
216
|
-
|
217
|
-
it "should ignore a wrong Content-Length when asked to" do
|
218
|
-
expect {
|
219
|
-
@session.ignore_content_length = true
|
220
|
-
@session.get("/wrongcontentlength")
|
221
|
-
}.to_not raise_error
|
222
|
-
end
|
223
|
-
|
224
|
-
it "should fail by default with a Content-Length too high" do
|
225
|
-
expect {
|
226
|
-
@session.ignore_content_length = nil
|
227
|
-
@session.get("/wrongcontentlength")
|
228
|
-
}.to raise_error(Patron::PartialFileError)
|
221
|
+
expect(yaml_load(response).header).to_not include('cookie')
|
229
222
|
end
|
230
223
|
|
231
224
|
it "should raise exception if cookie store is not writable or readable" do
|
@@ -254,14 +247,24 @@ describe Patron::Session do
|
|
254
247
|
|
255
248
|
it "should work when insecure mode is off but certificate is supplied" do
|
256
249
|
@session.insecure = nil
|
257
|
-
@session.cacert = '
|
250
|
+
@session.cacert = File.join(__dir__, 'support', 'certs', 'cacert.pem')
|
258
251
|
response = @session.get("/test")
|
259
|
-
body =
|
252
|
+
body = yaml_load(response.body)
|
260
253
|
expect(body.request_method).to be == "GET"
|
261
254
|
end
|
262
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
|
+
|
263
266
|
it "should work with different SSL versions" do
|
264
|
-
['
|
267
|
+
['TLSv1_0','TLSv1_1'].each do |version|
|
265
268
|
@session.ssl_version = version
|
266
269
|
response = @session.get("/test")
|
267
270
|
expect(response.status).to be == 200
|
data/spec/spec_helper.rb
CHANGED
@@ -18,5 +18,17 @@ $stderr.puts "Build against #{Patron.libcurl_version}"
|
|
18
18
|
|
19
19
|
Dir['./spec/support/**/*.rb'].each { |fn| require fn }
|
20
20
|
|
21
|
-
|
22
|
-
|
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
|
data/spec/support/config.ru
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'ostruct'
|
3
|
+
require 'zlib'
|
3
4
|
|
4
5
|
## HTTP test server for integration tests
|
5
6
|
|
@@ -25,7 +26,9 @@ Readback = Proc.new {|env|
|
|
25
26
|
end
|
26
27
|
|
27
28
|
fake_webrick_request_object = OpenStruct.new({
|
28
|
-
:
|
29
|
+
:fullpath => req.fullpath,
|
30
|
+
:path => req.path,
|
31
|
+
:query_string => req.query_string,
|
29
32
|
:request_method => req.request_method.to_s,
|
30
33
|
:header => Hash[req_headers],
|
31
34
|
:body => env['rack.input'].read,
|
@@ -38,16 +41,20 @@ Readback = Proc.new {|env|
|
|
38
41
|
GzipServlet = Proc.new {|env|
|
39
42
|
raise "Need to have the right Accept-Encoding: header" unless env['HTTP_ACCEPT_ENCODING']
|
40
43
|
|
41
|
-
body =
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
48
51
|
end
|
52
|
+
fin = z.finish.to_s
|
53
|
+
body << fin
|
54
|
+
content_length += fin.bytesize
|
55
|
+
z.close
|
49
56
|
|
50
|
-
[200, {'Content-Encoding' => 'deflate', 'Vary' => 'Accept-Encoding'}, body]
|
57
|
+
[200, {'Content-Encoding' => 'deflate', 'Content-Length' => content_length.to_s, 'Vary' => 'Accept-Encoding'}, body]
|
51
58
|
}
|
52
59
|
|
53
60
|
TimeoutServlet = Proc.new {|env|
|
@@ -60,15 +67,16 @@ TimeoutServlet = Proc.new {|env|
|
|
60
67
|
SlowServlet = Proc.new {|env|
|
61
68
|
body = Enumerator.new do |y|
|
62
69
|
y.yield 'x'
|
63
|
-
sleep
|
70
|
+
sleep 5
|
64
71
|
y.yield 'rest of body'
|
65
72
|
end
|
66
73
|
[200, {'Content-Type' => 'text/plain'}, body]
|
67
74
|
}
|
68
75
|
|
69
76
|
RedirectServlet = Proc.new {|env|
|
77
|
+
url_scheme = env.fetch('rack.url_scheme')
|
70
78
|
port = env.fetch('SERVER_PORT')
|
71
|
-
[301, {'Location' => "
|
79
|
+
[301, {'Location' => "#{url_scheme}://localhost:#{port}/test"}, []]
|
72
80
|
}
|
73
81
|
|
74
82
|
EvilRedirectServlet = Proc.new {|env|
|
@@ -76,8 +84,8 @@ EvilRedirectServlet = Proc.new {|env|
|
|
76
84
|
}
|
77
85
|
|
78
86
|
BodyReadback = Proc.new {|env|
|
79
|
-
readback = {'method' => env['REQUEST_METHOD'], 'body' => env['rack.input'].read, 'content_type' => env.fetch('
|
80
|
-
[200, {'Content-Type' => 'text/plain'}, [readback]]
|
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]]
|
81
89
|
}
|
82
90
|
|
83
91
|
TestPatchBodyServlet = BodyReadback
|
@@ -94,7 +102,13 @@ RepetitiveHeaderServlet = Proc.new {|env|
|
|
94
102
|
}
|
95
103
|
|
96
104
|
PictureServlet = Proc.new {|env|
|
97
|
-
|
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'}, []]
|
98
112
|
}
|
99
113
|
|
100
114
|
WrongContentLengthServlet = Proc.new {|env|
|
@@ -103,10 +117,11 @@ WrongContentLengthServlet = Proc.new {|env|
|
|
103
117
|
|
104
118
|
# Serves a substantial amount of data
|
105
119
|
LargeServlet = Proc.new {|env|
|
120
|
+
rng = Random.new
|
106
121
|
len = 15 * 1024 * 1024
|
107
122
|
body = Enumerator.new do |y|
|
108
123
|
15.times do
|
109
|
-
y.yield(
|
124
|
+
y.yield(rng.bytes(1024 * 1024))
|
110
125
|
end
|
111
126
|
end
|
112
127
|
[200, {'Content-Type' => 'binary/octet-stream', 'Content-Length' => len.to_s}, body]
|
@@ -122,6 +137,7 @@ run Rack::URLMap.new({
|
|
122
137
|
"/redirect" => RedirectServlet,
|
123
138
|
"/evil-redirect" => EvilRedirectServlet,
|
124
139
|
"/picture" => PictureServlet,
|
140
|
+
"/redirect-to-picture" => RedirectToPictureServlet,
|
125
141
|
"/very-large" => LargeServlet,
|
126
142
|
"/setcookie" => SetCookieServlet,
|
127
143
|
"/repetitiveheader" => RepetitiveHeaderServlet,
|
@@ -0,0 +1,70 @@
|
|
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
CHANGED
@@ -3,18 +3,24 @@ require 'puma'
|
|
3
3
|
require 'rack/handler/puma'
|
4
4
|
|
5
5
|
class PatronTestServer
|
6
|
-
APP = Rack::Builder.new { eval(File.read(File.
|
6
|
+
APP = Rack::Builder.new { eval(File.read(File.join(__dir__, 'config.ru'))) }
|
7
7
|
|
8
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')
|
9
15
|
@ssl = ssl
|
10
|
-
keypath = File.
|
11
|
-
certpath = File.
|
16
|
+
keypath = File.join(__dir__, 'certs', 'privkey.pem')
|
17
|
+
certpath = File.join(__dir__, 'certs', 'cacert.pem')
|
12
18
|
|
13
19
|
host = if ssl
|
14
|
-
'ssl://
|
20
|
+
'ssl://0.0.0.0:%d?key=%s&cert=%s' % [port, keypath, certpath]
|
15
21
|
else
|
16
|
-
'
|
22
|
+
'0.0.0.0'
|
17
23
|
end
|
18
|
-
Rack::Handler::Puma.run(APP, {:Port => port.to_i, :Verbose => true, :Host =>
|
24
|
+
Rack::Handler::Puma.run(APP, {:Port => port.to_i, :Verbose => true, :Host => host})
|
19
25
|
end
|
20
26
|
end
|
metadata
CHANGED
@@ -1,136 +1,24 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: patron
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.13.
|
4
|
+
version: 0.13.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
8
|
-
autorequire:
|
7
|
+
- Aeryn Riley Dowling-Toland
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: rake
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '10'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '10'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: bundler
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '1'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '1'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rspec
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: 2.3.0
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: 2.3.0
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: simplecov
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0.10'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0.10'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: yard
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: 0.9.11
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: 0.9.11
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rack
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '1'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '1'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: puma
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - "~>"
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '3.11'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - "~>"
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '3.11'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: rake-compiler
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ">="
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
10
|
+
date: 2025-02-27 00:00:00.000000000 Z
|
11
|
+
dependencies: []
|
125
12
|
description: Ruby HTTP client library based on libcurl
|
126
13
|
email:
|
127
|
-
-
|
14
|
+
- aeryn.toland@gmail.com
|
128
15
|
executables: []
|
129
16
|
extensions:
|
130
17
|
- ext/patron/extconf.rb
|
131
18
|
extra_rdoc_files: []
|
132
19
|
files:
|
133
20
|
- ".autotest"
|
21
|
+
- ".github/workflows/ci.yml"
|
134
22
|
- ".gitignore"
|
135
23
|
- ".rspec"
|
136
24
|
- ".travis.yml"
|
@@ -160,8 +48,6 @@ files:
|
|
160
48
|
- pic.png
|
161
49
|
- script/console
|
162
50
|
- script/test_server
|
163
|
-
- spec/certs/cacert.pem
|
164
|
-
- spec/certs/privkey.pem
|
165
51
|
- spec/header_parser_spec.rb
|
166
52
|
- spec/patron_spec.rb
|
167
53
|
- spec/request_spec.rb
|
@@ -175,17 +61,21 @@ files:
|
|
175
61
|
- spec/session_spec.rb
|
176
62
|
- spec/session_ssl_spec.rb
|
177
63
|
- spec/spec_helper.rb
|
64
|
+
- spec/support/certs/cacert.pem
|
65
|
+
- spec/support/certs/privkey.pem
|
178
66
|
- spec/support/config.ru
|
67
|
+
- spec/support/fork.rb
|
179
68
|
- spec/support/test_server.rb
|
180
69
|
- spec/util_spec.rb
|
181
70
|
homepage: https://github.com/toland/patron
|
182
|
-
licenses:
|
71
|
+
licenses:
|
72
|
+
- MIT
|
183
73
|
metadata:
|
184
74
|
allowed_push_host: https://rubygems.org
|
185
75
|
post_install_message: |2
|
186
76
|
|
187
77
|
Thank you for installing Patron. On OSX, make sure you are using libCURL with OpenSSL.
|
188
|
-
SecureTransport-based builds might cause crashes in forking
|
78
|
+
SecureTransport-based builds might cause crashes in forking environments.
|
189
79
|
|
190
80
|
For more info see https://github.com/curl/curl/issues/788
|
191
81
|
rdoc_options: []
|
@@ -203,9 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
203
93
|
- !ruby/object:Gem::Version
|
204
94
|
version: 1.2.0
|
205
95
|
requirements: []
|
206
|
-
|
207
|
-
rubygems_version: 2.5.2
|
208
|
-
signing_key:
|
96
|
+
rubygems_version: 3.6.2
|
209
97
|
specification_version: 4
|
210
98
|
summary: Patron HTTP Client
|
211
99
|
test_files: []
|
File without changes
|
File without changes
|