patron 0.13.1 → 0.13.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +0 -4
- data/CHANGELOG.md +10 -1
- data/README.md +51 -30
- data/ext/patron/session_ext.c +28 -50
- data/lib/patron/version.rb +1 -1
- data/patron.gemspec +1 -1
- data/spec/patron_spec.rb +1 -1
- data/spec/session_spec.rb +8 -10
- data/spec/session_ssl_spec.rb +4 -19
- data/spec/spec_helper.rb +11 -2
- data/spec/{certs → support/certs}/cacert.pem +0 -0
- data/spec/{certs → support/certs}/privkey.pem +0 -0
- data/spec/support/config.ru +20 -12
- data/spec/support/test_server.rb +12 -6
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e766e45bfa71015943701e1340503df7f915d499cd001475649613175df4006d
|
4
|
+
data.tar.gz: 8b3a7d7fcb6d555dfff1705685c8685b925c900dfec95200816580028ffa9d53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 986e1bb343ea53368a6acb8f7d7ef84a48674408d4a08f7eabe1d2e2c6ff5c90f2afe0683d1e66ab751c72241a25c9f46c8e16c955c97b87c71a0bc2bd7db723
|
7
|
+
data.tar.gz: c285b097c1fc4022fce3484184ac44d471340a496bc246142233e655bfdf0a28653484490ce5b1802fac4d5b396bea8ca03cfd1c803867f7c07ff3d8a789335c
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,13 @@
|
|
1
|
-
### 0.13.
|
1
|
+
### 0.13.3
|
2
|
+
|
3
|
+
* Fix a number of specs that were failing due to use of threads
|
4
|
+
|
5
|
+
### 0.13.2
|
6
|
+
|
7
|
+
* Eagerly initialize libCURL handle when creating the Session instance instead of initializing it lazily
|
8
|
+
* Remove special treatment of `Session#reset` and make it the same as `Session#interrupt`
|
9
|
+
|
10
|
+
### 0.13.0, 0.13.1
|
2
11
|
|
3
12
|
* Permit timeouts to be set as a Float of seconds and use `CURLOPT_(CONNECT)TIMEOUT_MS` instead of `CURLOPT_(CONNECT)TIMEOUT` so that
|
4
13
|
sub-second timeouts can be configured, which is useful for performant services using accelerated DNS resolution.
|
data/README.md
CHANGED
@@ -50,10 +50,55 @@ You can ship custom headers with a single request:
|
|
50
50
|
|
51
51
|
sess.post("/foo/stuff", "some data", {"Content-Type" => "text/plain"})
|
52
52
|
|
53
|
-
##
|
53
|
+
## Threading
|
54
|
+
|
55
|
+
By itself, the `Patron::Session` objects are not thread safe (each `Session` holds a single `curl_state` pointer
|
56
|
+
from initialization to garbage collection). At this time, Patron has no support for `curl_multi_*` family of functions
|
57
|
+
for doing concurrent requests. However, the actual code that interacts with libCURL does unlock the RVM GIL,
|
58
|
+
so using multiple `Session` objects in different threads actually enables a high degree of parallelism.
|
59
|
+
For sharing a resource of sessions between threads we recommend using the excellent [connection_pool](https://rubygems.org/gems/connection_pool) gem by Mike Perham.
|
60
|
+
|
61
|
+
patron_pool = ConnectionPool.new(size: 5, timeout: 5) { Patron::Session.new }
|
62
|
+
patron_pool.with do |session|
|
63
|
+
session.get(...)
|
64
|
+
end
|
65
|
+
|
66
|
+
Sharing Session objects between requests will also allow you to benefit from persistent connections (connection reuse), see below.
|
67
|
+
|
68
|
+
## Persistent connections
|
69
|
+
|
70
|
+
Patron follows the libCURL guidelines on [connection reuse.](https://ec.haxx.se/libcurl-connectionreuse.html) If you create the Session
|
71
|
+
object once and use it for multiple requests, the same libCURL handle is going to be used across these requests and if requests go to
|
72
|
+
the same hostname/port/protocol the connection should get reused.
|
73
|
+
|
74
|
+
## Performance with parallel requests
|
75
|
+
|
76
|
+
When performing the libCURL request, Patron goes out of it's way to unlock the GVL (global VM lock) to allow other threads to be scheduled
|
77
|
+
in parallel. The GVL is going to be released when the libCURL request starts, and will then be shortly re-acquired to provide the progress
|
78
|
+
callback - if the callback has been configured, and then released again until the libCURL request has been performed and the response has
|
79
|
+
been read in full. This allows one to execute multiple libCURL requests in parallel, as well as perform other activities on other MRI threads
|
80
|
+
that are currently active in the process.
|
81
|
+
|
82
|
+
## Requirements
|
83
|
+
|
84
|
+
Patron uses encoding features of Ruby, so you need at least Ruby 1.9. Also, a
|
85
|
+
recent version of libCURL is required. We recommend at least 7.19.4 because
|
86
|
+
it [supports limiting the protocols](https://curl.haxx.se/libcurl/c/CURLOPT_PROTOCOLS.html),
|
87
|
+
and that is very important for security - especially if you follow redirects.
|
88
|
+
|
89
|
+
On OSX the provided libcurl is sufficient if you are not using fork+SSL combination (see below).
|
90
|
+
You will have to install the libcurl development packages on Debian or Ubuntu. Other Linux systems are probably
|
91
|
+
similar. For Windows we do not have an established build instruction at the moment, unfortunately.
|
92
|
+
|
93
|
+
Versions of Patron below 1.0 will maintain compatibility down to Ruby 1.9.3,
|
94
|
+
versions below 2.0 will maintain compatibility down to Ruby 2.3
|
95
|
+
|
96
|
+
## Forking webservers on macOS and SSL
|
54
97
|
|
55
|
-
Currently, [an issue is at play](https://github.com/curl/curl/issues/788) with OSX builds of `curl` which use
|
56
|
-
|
98
|
+
Currently, [an issue is at play](https://github.com/curl/curl/issues/788) with OSX builds of `curl` which use
|
99
|
+
Apple's SecureTransport. Such builds (which Patron is linking to), are causing segfaults when performing HTTPS
|
100
|
+
requests in forked subprocesses. If you need to check whether your system is affected,
|
101
|
+
run the Patron test suite by performing
|
57
102
|
|
58
103
|
$ bundle install && bundle exec rspec
|
59
104
|
|
@@ -69,37 +114,13 @@ When doing so, `curl` will use openssl as it's SSL driver. You also need to
|
|
69
114
|
change the Patron compile flag:
|
70
115
|
|
71
116
|
|
72
|
-
$ brew install curl
|
73
|
-
gem install patron --with-curl-config=/usr/local/opt/curl/bin/curl-config
|
117
|
+
$ brew install curl-openssl && \
|
118
|
+
gem install patron -- --with-curl-config=/usr/local/opt/curl-openssl/bin/curl-config
|
74
119
|
|
75
120
|
You can also save this parameter for all future Bundler-driven gem installs by
|
76
121
|
setting this flag in Bundler proper:
|
77
122
|
|
78
|
-
$ bundle config build.patron --with-curl-config=/usr/local/opt/curl/bin/curl-config
|
79
|
-
|
80
|
-
## Threading
|
81
|
-
|
82
|
-
By itself, the `Patron::Session` objects are not thread safe (each `Session` holds a single `curl_state` pointer
|
83
|
-
during the request/response cycle). At this time, Patron has no support for `curl_multi_*` family of functions
|
84
|
-
for doing concurrent requests. However, the actual code that interacts with libCURL does unlock the RVM GIL,
|
85
|
-
so using multiple `Session` objects in different threads is possible with a high degree of concurrency.
|
86
|
-
For sharing a resource of sessions between threads we recommend using the excellent [connection_pool](https://rubygems.org/gems/connection_pool) gem by Mike Perham.
|
87
|
-
|
88
|
-
patron_pool = ConnectionPool.new(size: 5, timeout: 5) { Patron::Session.new }
|
89
|
-
patron_pool.with do |session|
|
90
|
-
session.get(...)
|
91
|
-
end
|
92
|
-
|
93
|
-
## Requirements
|
94
|
-
|
95
|
-
Patron uses encoding features of Ruby, so you need at least Ruby 1.9. Also, a
|
96
|
-
recent version of libCURL is required. We recommend at least 7.19.4 because
|
97
|
-
it [supports limiting the protocols](https://curl.haxx.se/libcurl/c/CURLOPT_PROTOCOLS.html),
|
98
|
-
and that is very important for security - especially if you follow redirects.
|
99
|
-
|
100
|
-
On OSX the provided libcurl is sufficient. You will have to install the libcurl
|
101
|
-
development packages on Debian or Ubuntu. Other Linux systems are probably
|
102
|
-
similar. For Windows we do not have an established build instruction at the moment, unfortunately.
|
123
|
+
$ bundle config build.patron --with-curl-config=/usr/local/opt/curl-openssl/bin/curl-config
|
103
124
|
|
104
125
|
## Installation
|
105
126
|
|
data/ext/patron/session_ext.c
CHANGED
@@ -163,6 +163,7 @@ static void cs_list_remove(struct patron_curl_state *state) {
|
|
163
163
|
}
|
164
164
|
}
|
165
165
|
|
166
|
+
/* Gets attached to at_exit of the Ruby process to be able to abort all running libCURL requests and quit */
|
166
167
|
static void cs_list_interrupt(VALUE data) {
|
167
168
|
UNUSED_ARGUMENT(data);
|
168
169
|
|
@@ -182,7 +183,7 @@ static void session_close_debug_file(struct patron_curl_state *curl) {
|
|
182
183
|
curl->debug_file = NULL;
|
183
184
|
}
|
184
185
|
|
185
|
-
/* Cleans up the
|
186
|
+
/* Cleans up the patron_curl_state data when the Session object is garbage collected. */
|
186
187
|
void session_free(struct patron_curl_state *curl) {
|
187
188
|
if (curl->handle) {
|
188
189
|
curl_easy_cleanup(curl->handle);
|
@@ -201,12 +202,29 @@ void session_free(struct patron_curl_state *curl) {
|
|
201
202
|
|
202
203
|
/* Allocates patron_curl_state data needed for a new Session object. */
|
203
204
|
VALUE session_alloc(VALUE klass) {
|
204
|
-
struct patron_curl_state*
|
205
|
-
VALUE obj = Data_Make_Struct(klass, struct patron_curl_state, NULL, session_free,
|
206
|
-
|
207
|
-
membuffer_init(
|
208
|
-
membuffer_init(
|
209
|
-
cs_list_append(
|
205
|
+
struct patron_curl_state* state;
|
206
|
+
VALUE obj = Data_Make_Struct(klass, struct patron_curl_state, NULL, session_free, state);
|
207
|
+
|
208
|
+
membuffer_init(&state->header_buffer);
|
209
|
+
membuffer_init(&state->body_buffer);
|
210
|
+
cs_list_append(state);
|
211
|
+
|
212
|
+
/*
|
213
|
+
Eagerly initialize the curl handle. We initialize it only once and store it
|
214
|
+
in the struct until the Session object gets garbage-collected in session_free(). This allows libCURL to
|
215
|
+
reuse the TCP connection and can speed things up if the same resource - like a backend service -
|
216
|
+
gets accessed over and over with requests.
|
217
|
+
*/
|
218
|
+
state->handle = curl_easy_init();
|
219
|
+
curl_easy_setopt(state->handle, CURLOPT_NOSIGNAL, 1);
|
220
|
+
curl_easy_setopt(state->handle, CURLOPT_NOPROGRESS, 0);
|
221
|
+
#if LIBCURL_VERSION_NUM >= 0x072000
|
222
|
+
/* this is libCURLv7.32.0 or later, supports CURLOPT_XFERINFOFUNCTION */
|
223
|
+
curl_easy_setopt(state->handle, CURLOPT_XFERINFOFUNCTION, &session_progress_handler);
|
224
|
+
#else
|
225
|
+
curl_easy_setopt(state->handle, CURLOPT_PROGRESSFUNCTION, &session_progress_handler);
|
226
|
+
#endif
|
227
|
+
curl_easy_setopt(state->handle, CURLOPT_PROGRESSDATA, state);
|
210
228
|
|
211
229
|
return obj;
|
212
230
|
}
|
@@ -215,25 +233,9 @@ VALUE session_alloc(VALUE klass) {
|
|
215
233
|
static struct patron_curl_state* get_patron_curl_state(VALUE self) {
|
216
234
|
struct patron_curl_state* state;
|
217
235
|
Data_Get_Struct(self, struct patron_curl_state, state);
|
218
|
-
|
219
|
-
if (NULL == state->handle) {
|
220
|
-
state->handle = curl_easy_init();
|
221
|
-
curl_easy_setopt(state->handle, CURLOPT_NOSIGNAL, 1);
|
222
|
-
curl_easy_setopt(state->handle, CURLOPT_NOPROGRESS, 0);
|
223
|
-
#if LIBCURL_VERSION_NUM >= 0x072000
|
224
|
-
/* this is libCURLv7.32.0 or later, supports CURLOPT_XFERINFOFUNCTION */
|
225
|
-
curl_easy_setopt(state->handle, CURLOPT_XFERINFOFUNCTION, &session_progress_handler);
|
226
|
-
#else
|
227
|
-
curl_easy_setopt(state->handle, CURLOPT_PROGRESSFUNCTION, &session_progress_handler);
|
228
|
-
#endif
|
229
|
-
|
230
|
-
curl_easy_setopt(state->handle, CURLOPT_PROGRESSDATA, state);
|
231
|
-
}
|
232
|
-
|
233
236
|
return state;
|
234
237
|
}
|
235
238
|
|
236
|
-
|
237
239
|
/*----------------------------------------------------------------------------*/
|
238
240
|
/* Method implementations */
|
239
241
|
|
@@ -887,33 +889,9 @@ static VALUE session_handle_request(VALUE self, VALUE request) {
|
|
887
889
|
return rb_ensure(&perform_request, self, &cleanup, self);
|
888
890
|
}
|
889
891
|
|
890
|
-
/*
|
891
|
-
* FIXME: figure out how this method should be used at all given Session is not multithreaded.
|
892
|
-
* FIXME: also: what is the difference with `interrupt()` and also relationship with `cleanup()`?
|
893
|
-
* Reset the underlying cURL session. This effectively closes all open
|
894
|
-
* connections and disables debug output. There is no need to call this method
|
895
|
-
* manually after performing a request, since cleanup is performed automatically
|
896
|
-
* but the method can be used from another thread
|
897
|
-
* to abort a request currently in progress.
|
898
|
-
*
|
899
|
-
* @return self
|
900
|
-
*/
|
901
|
-
static VALUE session_reset(VALUE self) {
|
902
|
-
struct patron_curl_state *state;
|
903
|
-
Data_Get_Struct(self, struct patron_curl_state, state);
|
904
|
-
|
905
|
-
if (NULL != state->handle) {
|
906
|
-
cleanup(self);
|
907
|
-
curl_easy_cleanup(state->handle);
|
908
|
-
state->handle = NULL;
|
909
|
-
session_close_debug_file(state);
|
910
|
-
}
|
911
|
-
|
912
|
-
return self;
|
913
|
-
}
|
914
|
-
|
915
892
|
/* Interrupt any currently executing request. This will cause the current
|
916
|
-
* request to error and raise an exception.
|
893
|
+
* request to error and raise an exception. The method can be called from another thread to
|
894
|
+
* abort the request in-flight.
|
917
895
|
*
|
918
896
|
* @return [void] This method always raises
|
919
897
|
*/
|
@@ -1009,7 +987,7 @@ void Init_session_ext() {
|
|
1009
987
|
rb_define_method(cSession, "unescape", session_unescape, 1);
|
1010
988
|
|
1011
989
|
rb_define_method(cSession, "handle_request", session_handle_request, 1);
|
1012
|
-
rb_define_method(cSession, "reset",
|
990
|
+
rb_define_method(cSession, "reset", session_interrupt, 0);
|
1013
991
|
rb_define_method(cSession, "interrupt", session_interrupt, 0);
|
1014
992
|
rb_define_method(cSession, "add_cookie_file", add_cookie_file, 1);
|
1015
993
|
rb_define_method(cSession, "set_debug_file", set_debug_file, 1);
|
data/lib/patron/version.rb
CHANGED
data/patron.gemspec
CHANGED
@@ -36,7 +36,7 @@ SecureTransport-based builds might cause crashes in forking environment.
|
|
36
36
|
For more info see https://github.com/curl/curl/issues/788
|
37
37
|
}
|
38
38
|
spec.add_development_dependency "rake", "~> 10"
|
39
|
-
spec.add_development_dependency "bundler"
|
39
|
+
spec.add_development_dependency "bundler"
|
40
40
|
spec.add_development_dependency "rspec", ">= 2.3.0"
|
41
41
|
spec.add_development_dependency "simplecov", "~> 0.10"
|
42
42
|
spec.add_development_dependency "yard", "~> 0.9.11"
|
data/spec/patron_spec.rb
CHANGED
@@ -10,7 +10,7 @@ describe Patron do
|
|
10
10
|
|
11
11
|
it "should return the version number of the Patron library" do
|
12
12
|
version = Patron.version
|
13
|
-
expect(version).to match(%r|^\d+.\d+.\d
|
13
|
+
expect(version).to match(%r|^\d+.\d+.\d+(\.\w+\.\d+)?$|)
|
14
14
|
end
|
15
15
|
|
16
16
|
it "should return the version string of the libcurl library" do
|
data/spec/session_spec.rb
CHANGED
@@ -16,9 +16,9 @@ describe Patron::Session do
|
|
16
16
|
forbidden_protos = %w( smb tftp imap smtp telnet dict ftp sftp scp file gopher )
|
17
17
|
forbidden_protos.each do |forbidden_proto|
|
18
18
|
it "should deny a #{forbidden_proto.upcase} request" do
|
19
|
-
@session.base_url = nil
|
20
19
|
expect {
|
21
|
-
@session.
|
20
|
+
@session.base_url = '%s://localhost' % forbidden_proto
|
21
|
+
@session.get('')
|
22
22
|
}.to raise_error(Patron::UnsupportedProtocol)
|
23
23
|
end
|
24
24
|
end
|
@@ -208,9 +208,9 @@ describe Patron::Session do
|
|
208
208
|
end
|
209
209
|
|
210
210
|
it "is able to terminate the thread that is running a slow request" do
|
211
|
-
|
211
|
+
pid = Process.fork do
|
212
212
|
trap('SIGINT') do
|
213
|
-
exit # exit the
|
213
|
+
exit # exit the process
|
214
214
|
end
|
215
215
|
session = Patron::Session.new
|
216
216
|
session.timeout = 40
|
@@ -222,8 +222,8 @@ describe Patron::Session do
|
|
222
222
|
# using a signal during that time.
|
223
223
|
started = Time.now.to_i
|
224
224
|
sleep 5 # Less than what it takes for the server to respond
|
225
|
-
Process.kill("INT",
|
226
|
-
|
225
|
+
Process.kill("INT", pid) # Signal ourselves...
|
226
|
+
Process.wait(pid) # wrap up the process. If Patron is still busy there, this call will still take 15s.
|
227
227
|
delta_s = Time.now.to_i - started
|
228
228
|
expect(delta_s).to be_within(2).of(5)
|
229
229
|
end
|
@@ -458,14 +458,14 @@ describe Patron::Session do
|
|
458
458
|
it "should ignore a wrong Content-Length when asked to" do
|
459
459
|
expect {
|
460
460
|
@session.ignore_content_length = true
|
461
|
-
@session.get("/wrongcontentlength")
|
461
|
+
@session.get("/wrongcontentlength", { 'Connection' => 'close' })
|
462
462
|
}.to_not raise_error
|
463
463
|
end
|
464
464
|
|
465
465
|
it "should fail by default with a Content-Length too high" do
|
466
466
|
expect {
|
467
467
|
@session.ignore_content_length = nil
|
468
|
-
@session.get("/wrongcontentlength")
|
468
|
+
@session.get("/wrongcontentlength", { 'Connection' => 'close' })
|
469
469
|
}.to raise_error(Patron::PartialFileError)
|
470
470
|
end
|
471
471
|
|
@@ -517,14 +517,12 @@ describe Patron::Session do
|
|
517
517
|
it "should serialize query params and append them to the url" do
|
518
518
|
response = @session.request(:get, "/test", {}, :query => {:foo => "bar"})
|
519
519
|
request = YAML::load(response.body)
|
520
|
-
request.parse
|
521
520
|
expect(request.path + '?' + request.query_string).to be == "/test?foo=bar"
|
522
521
|
end
|
523
522
|
|
524
523
|
it "should merge parameters in the :query option with pre-existing query parameters" do
|
525
524
|
response = @session.request(:get, "/test?foo=bar", {}, :query => {:baz => "quux"})
|
526
525
|
request = YAML::load(response.body)
|
527
|
-
request.parse
|
528
526
|
expect(request.path + '?' + request.query_string).to be == "/test?foo=bar&baz=quux"
|
529
527
|
end
|
530
528
|
|
data/spec/session_ssl_spec.rb
CHANGED
@@ -32,12 +32,11 @@ describe Patron::Session do
|
|
32
32
|
it "should download content in a forked subprocess" do
|
33
33
|
# To trigger the bug, we need to perform a request in the master process first
|
34
34
|
tmpfile = "/tmp/patron_test.yaml"
|
35
|
-
@session.get_file "/
|
36
|
-
|
35
|
+
@session.get_file "/test", tmpfile
|
36
|
+
FileUtils.rm tmpfile
|
37
37
|
|
38
38
|
# and this one segfaults
|
39
39
|
pid = fork do
|
40
|
-
tmpfile = "/tmp/patron_test.yaml"
|
41
40
|
response = @session.get_file "/test", tmpfile
|
42
41
|
expect(response.body).to be_nil
|
43
42
|
body = YAML::load_file(tmpfile)
|
@@ -214,20 +213,6 @@ describe Patron::Session do
|
|
214
213
|
expect(YAML::load(response).header).to_not include('cookie')
|
215
214
|
end
|
216
215
|
|
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)
|
229
|
-
end
|
230
|
-
|
231
216
|
it "should raise exception if cookie store is not writable or readable" do
|
232
217
|
expect { @session.handle_cookies("/trash/clash/foo") }.to raise_error(ArgumentError)
|
233
218
|
end
|
@@ -254,14 +239,14 @@ describe Patron::Session do
|
|
254
239
|
|
255
240
|
it "should work when insecure mode is off but certificate is supplied" do
|
256
241
|
@session.insecure = nil
|
257
|
-
@session.cacert = '
|
242
|
+
@session.cacert = File.join(__dir__, 'support', 'certs', 'cacert.pem')
|
258
243
|
response = @session.get("/test")
|
259
244
|
body = YAML::load(response.body)
|
260
245
|
expect(body.request_method).to be == "GET"
|
261
246
|
end
|
262
247
|
|
263
248
|
it "should work with different SSL versions" do
|
264
|
-
['
|
249
|
+
['TLSv1_0','TLSv1_1'].each do |version|
|
265
250
|
@session.ssl_version = version
|
266
251
|
response = @session.get("/test")
|
267
252
|
expect(response.status).to be == 200
|
data/spec/spec_helper.rb
CHANGED
@@ -18,5 +18,14 @@ $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_pid = Process.fork { PatronTestServer.start(false, 9001) }
|
22
|
+
https_server_pid = Process.fork { PatronTestServer.start(true, 9043) }
|
23
|
+
|
24
|
+
RSpec.configure do |c|
|
25
|
+
c.after(:suite) do
|
26
|
+
Process.kill("INT", http_server_pid)
|
27
|
+
Process.kill("INT", https_server_pid)
|
28
|
+
Process.wait(http_server_pid)
|
29
|
+
Process.wait(https_server_pid)
|
30
|
+
end
|
31
|
+
end
|
File without changes
|
File without changes
|
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|
|
@@ -67,8 +74,9 @@ SlowServlet = Proc.new {|env|
|
|
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
|
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,14 +1,14 @@
|
|
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.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Phillip Toland
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -160,8 +160,6 @@ files:
|
|
160
160
|
- pic.png
|
161
161
|
- script/console
|
162
162
|
- script/test_server
|
163
|
-
- spec/certs/cacert.pem
|
164
|
-
- spec/certs/privkey.pem
|
165
163
|
- spec/header_parser_spec.rb
|
166
164
|
- spec/patron_spec.rb
|
167
165
|
- spec/request_spec.rb
|
@@ -175,6 +173,8 @@ files:
|
|
175
173
|
- spec/session_spec.rb
|
176
174
|
- spec/session_ssl_spec.rb
|
177
175
|
- spec/spec_helper.rb
|
176
|
+
- spec/support/certs/cacert.pem
|
177
|
+
- spec/support/certs/privkey.pem
|
178
178
|
- spec/support/config.ru
|
179
179
|
- spec/support/test_server.rb
|
180
180
|
- spec/util_spec.rb
|
@@ -204,7 +204,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
204
204
|
version: 1.2.0
|
205
205
|
requirements: []
|
206
206
|
rubyforge_project: patron
|
207
|
-
rubygems_version: 2.
|
207
|
+
rubygems_version: 2.7.6
|
208
208
|
signing_key:
|
209
209
|
specification_version: 4
|
210
210
|
summary: Patron HTTP Client
|