ethon 0.5.12 → 0.6.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 (66) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +11 -0
  5. data/CHANGELOG.md +5 -0
  6. data/Gemfile +1 -1
  7. data/Guardfile +9 -0
  8. data/ethon.gemspec +26 -0
  9. data/lib/ethon/curl.rb +0 -12
  10. data/lib/ethon/curls/constants.rb +6 -22
  11. data/lib/ethon/curls/functions.rb +38 -41
  12. data/lib/ethon/curls/infos.rb +19 -0
  13. data/lib/ethon/curls/options.rb +416 -219
  14. data/lib/ethon/curls/settings.rb +1 -0
  15. data/lib/ethon/easy.rb +12 -18
  16. data/lib/ethon/easy/callbacks.rb +40 -6
  17. data/lib/ethon/easy/debug_info.rb +46 -0
  18. data/lib/ethon/easy/mirror.rb +39 -0
  19. data/lib/ethon/easy/options.rb +17 -1235
  20. data/lib/ethon/easy/queryable.rb +6 -8
  21. data/lib/ethon/easy/response_callbacks.rb +1 -1
  22. data/lib/ethon/version.rb +1 -1
  23. data/profile/benchmarks.rb +137 -0
  24. data/profile/memory_leaks.rb +113 -0
  25. data/profile/perf_spec_helper.rb +36 -0
  26. data/profile/support/memory_test_helpers.rb +75 -0
  27. data/profile/support/os_memory_leak_tracker.rb +47 -0
  28. data/profile/support/ruby_object_leak_tracker.rb +48 -0
  29. data/spec/ethon/curl_spec.rb +27 -0
  30. data/spec/ethon/easy/callbacks_spec.rb +31 -0
  31. data/spec/ethon/easy/debug_info_spec.rb +52 -0
  32. data/spec/ethon/easy/form_spec.rb +76 -0
  33. data/spec/ethon/easy/header_spec.rb +78 -0
  34. data/spec/ethon/easy/http/custom_spec.rb +176 -0
  35. data/spec/ethon/easy/http/delete_spec.rb +20 -0
  36. data/spec/ethon/easy/http/get_spec.rb +89 -0
  37. data/spec/ethon/easy/http/head_spec.rb +79 -0
  38. data/spec/ethon/easy/http/options_spec.rb +50 -0
  39. data/spec/ethon/easy/http/patch_spec.rb +50 -0
  40. data/spec/ethon/easy/http/post_spec.rb +220 -0
  41. data/spec/ethon/easy/http/put_spec.rb +124 -0
  42. data/spec/ethon/easy/http_spec.rb +44 -0
  43. data/spec/ethon/easy/informations_spec.rb +82 -0
  44. data/spec/ethon/easy/mirror_spec.rb +39 -0
  45. data/spec/ethon/easy/operations_spec.rb +251 -0
  46. data/spec/ethon/easy/options_spec.rb +135 -0
  47. data/spec/ethon/easy/queryable_spec.rb +188 -0
  48. data/spec/ethon/easy/response_callbacks_spec.rb +50 -0
  49. data/spec/ethon/easy/util_spec.rb +27 -0
  50. data/spec/ethon/easy_spec.rb +105 -0
  51. data/spec/ethon/libc_spec.rb +13 -0
  52. data/spec/ethon/loggable_spec.rb +21 -0
  53. data/spec/ethon/multi/operations_spec.rb +297 -0
  54. data/spec/ethon/multi/options_spec.rb +70 -0
  55. data/spec/ethon/multi/stack_spec.rb +79 -0
  56. data/spec/ethon/multi_spec.rb +21 -0
  57. data/spec/spec_helper.rb +27 -0
  58. data/spec/support/localhost_server.rb +94 -0
  59. data/spec/support/server.rb +114 -0
  60. metadata +91 -31
  61. data/lib/ethon/curls/auth_types.rb +0 -25
  62. data/lib/ethon/curls/http_versions.rb +0 -22
  63. data/lib/ethon/curls/postredir.rb +0 -15
  64. data/lib/ethon/curls/protocols.rb +0 -36
  65. data/lib/ethon/curls/proxy_types.rb +0 -25
  66. data/lib/ethon/curls/ssl_versions.rb +0 -23
@@ -0,0 +1,124 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ethon::Easy::Http::Put do
4
+ let(:easy) { Ethon::Easy.new }
5
+ let(:url) { "http://localhost:3001/" }
6
+ let(:params) { nil }
7
+ let(:form) { nil }
8
+ let(:put) { described_class.new(url, {:params => params, :body => form}) }
9
+
10
+ describe "#setup" do
11
+ context "when nothing" do
12
+ it "sets url" do
13
+ put.setup(easy)
14
+ expect(easy.url).to eq(url)
15
+ end
16
+
17
+ it "sets upload" do
18
+ easy.should_receive(:upload=).with(true)
19
+ put.setup(easy)
20
+ end
21
+
22
+ it "sets infilesize" do
23
+ easy.should_receive(:infilesize=).with(0)
24
+ put.setup(easy)
25
+ end
26
+
27
+ context "when requesting" do
28
+ it "makes a put request" do
29
+ put.setup(easy)
30
+ easy.perform
31
+ expect(easy.response_body).to include('"REQUEST_METHOD":"PUT"')
32
+ end
33
+ end
34
+ end
35
+
36
+ context "when params" do
37
+ let(:params) { {:a => "1&"} }
38
+
39
+ it "attaches escaped to url" do
40
+ put.setup(easy)
41
+ expect(easy.url).to eq("#{url}?a=1%26")
42
+ end
43
+
44
+ it "sets upload" do
45
+ easy.should_receive(:upload=).with(true)
46
+ put.setup(easy)
47
+ end
48
+
49
+ it "sets infilesize" do
50
+ easy.should_receive(:infilesize=).with(0)
51
+ put.setup(easy)
52
+ end
53
+
54
+ context "when requesting" do
55
+ before do
56
+ put.setup(easy)
57
+ easy.perform
58
+ end
59
+
60
+ it "makes a put request" do
61
+ expect(easy.response_body).to include('"REQUEST_METHOD":"PUT"')
62
+ end
63
+ end
64
+ end
65
+
66
+ context "when body" do
67
+ let(:form) { {:a => "1&b=2"} }
68
+
69
+ it "sets infilesize" do
70
+ easy.should_receive(:infilesize=).with(11)
71
+ put.setup(easy)
72
+ end
73
+
74
+ it "sets readfunction" do
75
+ easy.should_receive(:readfunction)
76
+ put.setup(easy)
77
+ end
78
+
79
+ it "sets upload" do
80
+ easy.should_receive(:upload=).with(true)
81
+ put.setup(easy)
82
+ end
83
+
84
+ context "when requesting" do
85
+ context "sending string body" do
86
+ before do
87
+ easy.headers = { 'Expect' => '' }
88
+ put.setup(easy)
89
+ easy.perform
90
+ end
91
+
92
+ it "makes a put request" do
93
+ expect(easy.response_body).to include('"REQUEST_METHOD":"PUT"')
94
+ end
95
+
96
+ it "submits a body" do
97
+ expect(easy.response_body).to include('"body":"a=1%26b%3D2"')
98
+ end
99
+ end
100
+
101
+ context "when injecting a file as body" do
102
+ let(:file) { File.open(__FILE__) }
103
+ let(:easy) do
104
+ e = Ethon::Easy.new(:url => url, :upload => true)
105
+ e.set_read_callback(file)
106
+ e.infilesize = File.size(file.path)
107
+ e
108
+ end
109
+
110
+ before do
111
+ easy.headers = { 'Expect' => '' }
112
+ easy.perform
113
+ end
114
+
115
+ it "submits file" do
116
+ expect(easy.response_body).to include("injecting")
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ context "when params and body"
123
+ end
124
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ethon::Easy::Http do
4
+ let(:easy) { Ethon::Easy.new }
5
+
6
+ describe "#http_request" do
7
+ let(:url) { "http://localhost:3001/" }
8
+ let(:action_name) { :get }
9
+ let(:options) { {} }
10
+
11
+ let(:get) { double(:setup) }
12
+ let(:get_class) { Ethon::Easy::Http::Get }
13
+
14
+ it "instanciates action" do
15
+ get.should_receive(:setup)
16
+ get_class.should_receive(:new).and_return(get)
17
+ easy.http_request(url, action_name, options)
18
+ end
19
+
20
+ context "when requesting" do
21
+ [ :get, :post, :put, :delete, :head, :patch, :options ].map do |action|
22
+ it "returns ok" do
23
+ easy.http_request(url, action, options)
24
+ easy.perform
25
+ expect(easy.return_code).to be(:ok)
26
+ end
27
+
28
+ unless action == :head
29
+ it "makes a #{action.to_s.upcase} request" do
30
+ easy.http_request(url, action, options)
31
+ easy.perform
32
+ expect(easy.response_body).to include("\"REQUEST_METHOD\":\"#{action.to_s.upcase}\"")
33
+ end
34
+ end
35
+ end
36
+
37
+ it "makes requests with custom HTTP verbs" do
38
+ easy.http_request(url, :purge, options)
39
+ easy.perform
40
+ expect(easy.response_body).to include(%{"REQUEST_METHOD":"PURGE"})
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ethon::Easy::Informations do
4
+ let(:easy) { Ethon::Easy.new }
5
+
6
+ before do
7
+ easy.url = "http://localhost:3001"
8
+ easy.perform
9
+ end
10
+
11
+ describe "#httpauth_avail" do
12
+ it "returns" do
13
+ expect(easy.httpauth_avail).to be
14
+ end
15
+ end
16
+
17
+ describe "#total_time" do
18
+ it "returns float" do
19
+ expect(easy.total_time).to be_a(Float)
20
+ end
21
+ end
22
+
23
+ describe "#starttransfer_time" do
24
+ it "returns float" do
25
+ expect(easy.starttransfer_time).to be_a(Float)
26
+ end
27
+ end
28
+
29
+ describe "#appconnect_time" do
30
+ it "returns float" do
31
+ expect(easy.appconnect_time).to be_a(Float)
32
+ end
33
+ end
34
+
35
+ describe "#pretransfer_time" do
36
+ it "returns float" do
37
+ expect(easy.pretransfer_time).to be_a(Float)
38
+ end
39
+ end
40
+
41
+ describe "#connect_time" do
42
+ it "returns float" do
43
+ expect(easy.connect_time).to be_a(Float)
44
+ end
45
+ end
46
+
47
+ describe "#namelookup_time" do
48
+ it "returns float" do
49
+ expect(easy.namelookup_time).to be_a(Float)
50
+ end
51
+ end
52
+
53
+ describe "#effective_url" do
54
+ it "returns url" do
55
+ expect(easy.effective_url).to match(/^http:\/\/localhost:3001\/?/)
56
+ end
57
+ end
58
+
59
+ describe "#primary_ip" do
60
+ it "returns localhost" do
61
+ expect(easy.primary_ip).to match(/::1|127\.0\.0\.1/)
62
+ end
63
+ end
64
+
65
+ describe "#response_code" do
66
+ it "returns 200" do
67
+ expect(easy.response_code).to eq(200)
68
+ end
69
+ end
70
+
71
+ describe "#redirect_count" do
72
+ it "returns 0" do
73
+ expect(easy.redirect_count).to eq(0)
74
+ end
75
+ end
76
+
77
+ describe "#supports_zlib?" do
78
+ it "returns true" do
79
+ expect(easy.supports_zlib?).to be_true
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ethon::Easy::Mirror do
4
+ let(:options) { nil }
5
+ let(:mirror) { described_class.new(options) }
6
+
7
+ describe ".informations_to_mirror" do
8
+ [
9
+ :return_code, :response_code, :response_body, :response_headers,
10
+ :total_time, :starttransfer_time, :appconnect_time,
11
+ :pretransfer_time, :connect_time, :namelookup_time,
12
+ :effective_url, :primary_ip, :redirect_count, :debug_info
13
+ ].each do |name|
14
+ it "contains #{name}" do
15
+ expect(described_class.informations_to_mirror).to include(name)
16
+ end
17
+ end
18
+ end
19
+
20
+ describe "#to_hash" do
21
+ let(:options) { {:return_code => 1} }
22
+
23
+ it "returns mirror as hash" do
24
+ expect(mirror.to_hash).to eq(options)
25
+ end
26
+ end
27
+
28
+ describe "#log_informations" do
29
+ let(:options) { {:return_code => 1} }
30
+
31
+ it "returns hash" do
32
+ expect(mirror.log_informations).to be_a(Hash)
33
+ end
34
+
35
+ it "includes return code" do
36
+ expect(mirror.log_informations).to include(options)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,251 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ethon::Easy::Operations do
4
+ let(:easy) { Ethon::Easy.new }
5
+
6
+ describe "#handle" do
7
+ it "returns a pointer" do
8
+ expect(easy.handle).to be_a(FFI::Pointer)
9
+ end
10
+ end
11
+
12
+
13
+ describe "#perform" do
14
+ let(:url) { nil }
15
+ let(:timeout) { nil }
16
+ let(:connect_timeout) { nil }
17
+ let(:follow_location) { nil }
18
+ let(:max_redirs) { nil }
19
+ let(:user_pwd) { nil }
20
+ let(:http_auth) { nil }
21
+ let(:headers) { nil }
22
+ let(:protocols) { nil }
23
+ let(:redir_protocols) { nil }
24
+ let(:username) { nil }
25
+ let(:password) { nil }
26
+
27
+ before do
28
+ easy.url = url
29
+ easy.timeout = timeout
30
+ easy.connecttimeout = connect_timeout
31
+ easy.followlocation = follow_location
32
+ easy.maxredirs = max_redirs
33
+ easy.httpauth = http_auth
34
+ easy.headers = headers
35
+ easy.protocols = protocols
36
+ easy.redir_protocols = redir_protocols
37
+
38
+ if user_pwd
39
+ easy.userpwd = user_pwd
40
+ else
41
+ easy.username = username
42
+ easy.password = password
43
+ end
44
+
45
+ easy.perform
46
+ end
47
+
48
+ it "calls Curl.easy_perform" do
49
+ Ethon::Curl.should_receive(:easy_perform)
50
+ easy.perform
51
+ end
52
+
53
+ context "when url" do
54
+ let(:url) { "http://localhost:3001/" }
55
+
56
+ it "returns ok" do
57
+ expect(easy.return_code).to eq(:ok)
58
+ end
59
+
60
+ it "sets response body" do
61
+ expect(easy.response_body).to be
62
+ end
63
+
64
+ it "sets response headers" do
65
+ expect(easy.response_headers).to be
66
+ end
67
+
68
+ context "when request timed out" do
69
+ let(:url) { "http://localhost:3001/?delay=1" }
70
+ let(:timeout) { 1 }
71
+
72
+ it "returns operation_timedout" do
73
+ expect(easy.return_code).to eq(:operation_timedout)
74
+ end
75
+ end
76
+
77
+ context "when connection timed out" do
78
+ let(:url) { "http://localhost:3009" }
79
+ let(:connect_timeout) { 1 }
80
+
81
+ it "returns couldnt_connect" do
82
+ expect(easy.return_code).to eq(:couldnt_connect)
83
+ end
84
+ end
85
+
86
+ context "when no follow location" do
87
+ let(:url) { "http://localhost:3001/redirect" }
88
+ let(:follow_location) { false }
89
+
90
+ it "doesn't follow" do
91
+ expect(easy.response_code).to eq(302)
92
+ end
93
+ end
94
+
95
+ context "when follow location" do
96
+ let(:url) { "http://localhost:3001/redirect" }
97
+ let(:follow_location) { true }
98
+
99
+ it "follows" do
100
+ expect(easy.response_code).to eq(200)
101
+ end
102
+
103
+ context "when infinite redirect loop" do
104
+ let(:url) { "http://localhost:3001/bad_redirect" }
105
+ let(:max_redirs) { 5 }
106
+
107
+ context "when max redirect set" do
108
+ it "follows only x times" do
109
+ expect(easy.response_code).to eq(302)
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ context "when user agent" do
116
+ let(:headers) { { 'User-Agent' => 'Ethon' } }
117
+
118
+ it "sets" do
119
+ expect(easy.response_body).to include('"HTTP_USER_AGENT":"Ethon"')
120
+ end
121
+ end
122
+ end
123
+
124
+ context "when auth url" do
125
+ before { easy.url = url }
126
+
127
+ context "when basic auth" do
128
+ let(:url) { "http://localhost:3001/auth_basic/username/password" }
129
+
130
+ context "when no user_pwd" do
131
+ it "returns 401" do
132
+ expect(easy.response_code).to eq(401)
133
+ end
134
+ end
135
+
136
+ context "when invalid user_pwd" do
137
+ let(:user_pwd) { "invalid:invalid" }
138
+
139
+ it "returns 401" do
140
+ expect(easy.response_code).to eq(401)
141
+ end
142
+ end
143
+
144
+ context "when valid user_pwd" do
145
+ let(:user_pwd) { "username:password" }
146
+
147
+ it "returns 200" do
148
+ expect(easy.response_code).to eq(200)
149
+ end
150
+ end
151
+
152
+ context "when user and password" do
153
+ let(:username) { "username" }
154
+ let(:password) { "password" }
155
+
156
+ it "returns 200" do
157
+ expect(easy.response_code).to eq(200)
158
+ end
159
+ end
160
+ end
161
+
162
+ context "when ntlm" do
163
+ let(:url) { "http://localhost:3001/auth_ntlm" }
164
+ let(:http_auth) { :ntlm }
165
+
166
+ context "when no user_pwd" do
167
+ it "returns 401" do
168
+ expect(easy.response_code).to eq(401)
169
+ end
170
+ end
171
+
172
+ context "when user_pwd" do
173
+ let(:user_pwd) { "username:password" }
174
+
175
+ it "returns 200" do
176
+ expect(easy.response_code).to eq(200)
177
+ end
178
+ end
179
+ end
180
+ end
181
+
182
+ context "when protocols" do
183
+ context "when asking for a allowed url" do
184
+ let(:url) { "http://localhost:3001" }
185
+ let(:protocols) { :http }
186
+
187
+ it "returns ok" do
188
+ expect(easy.return_code).to be(:ok)
189
+ end
190
+ end
191
+
192
+ context "when asking for a not allowed url" do
193
+ let(:url) { "http://localhost:3001" }
194
+ let(:protocols) { :https }
195
+
196
+ it "returns unsupported_protocol" do
197
+ expect(easy.return_code).to be(:unsupported_protocol)
198
+ end
199
+ end
200
+ end
201
+
202
+ context "when multiple protocols" do
203
+ context "when asking for a allowed url" do
204
+ let(:protocols) { [:http, :https] }
205
+
206
+ context "when http" do
207
+ let(:url) { "http://localhost:3001" }
208
+
209
+ it "returns ok for http" do
210
+ expect(easy.return_code).to be(:ok)
211
+ end
212
+ end
213
+
214
+ context "when https" do
215
+ let(:url) { "https://localhost:3001" }
216
+
217
+ it "returns ssl_connect_error for https" do
218
+ expect(easy.return_code).to be(:ssl_connect_error)
219
+ end
220
+ end
221
+ end
222
+
223
+ context "when asking for a not allowed url" do
224
+ let(:url) { "ssh://localhost" }
225
+ let(:protocols) { [:https, :http] }
226
+
227
+ it "returns unsupported_protocol" do
228
+ expect(easy.return_code).to be(:unsupported_protocol)
229
+ end
230
+ end
231
+ end
232
+
233
+ context "when redir_protocols" do
234
+ context "when redirecting to a not allowed url" do
235
+ let(:url) { "http://localhost:3001/redirect" }
236
+ let(:follow_location) { true }
237
+ let(:redir_protocols) { :https }
238
+
239
+ it "returns unsupported_protocol" do
240
+ expect(easy.return_code).to be(:unsupported_protocol)
241
+ end
242
+ end
243
+ end
244
+
245
+ context "when no url" do
246
+ it "returns url_malformat" do
247
+ expect(easy.perform).to eq(:url_malformat)
248
+ end
249
+ end
250
+ end
251
+ end