puffing-billy 3.0.0 → 3.0.1

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/lib/billy/browsers/capybara.rb +13 -9
  4. data/lib/billy/version.rb +1 -1
  5. metadata +9 -73
  6. data/.github/workflows/ci.yml +0 -27
  7. data/.gitignore +0 -6
  8. data/.rspec +0 -2
  9. data/Dockerfile +0 -14
  10. data/Gemfile +0 -4
  11. data/Guardfile +0 -23
  12. data/Rakefile +0 -11
  13. data/bin/proxy.rb +0 -3
  14. data/examples/README.md +0 -1
  15. data/examples/facebook_api.html +0 -59
  16. data/examples/intercept_request.html +0 -10
  17. data/examples/post_api.html +0 -16
  18. data/examples/preflight_request.html +0 -22
  19. data/examples/tumblr_api.html +0 -22
  20. data/examples/tumblr_api_https.html +0 -22
  21. data/lib/tasks/billy.rake +0 -87
  22. data/log/.gitkeep +0 -0
  23. data/puffing-billy.gemspec +0 -41
  24. data/spec/features/examples/facebook_api_spec.rb +0 -23
  25. data/spec/features/examples/intercept_request_spec.rb +0 -31
  26. data/spec/features/examples/post_api_spec.rb +0 -15
  27. data/spec/features/examples/preflight_request_spec.rb +0 -29
  28. data/spec/features/examples/tumblr_api_spec.rb +0 -59
  29. data/spec/lib/billy/browsers/capybara_spec.rb +0 -28
  30. data/spec/lib/billy/cache_spec.rb +0 -158
  31. data/spec/lib/billy/handlers/cache_handler_spec.rb +0 -191
  32. data/spec/lib/billy/handlers/handler_spec.rb +0 -16
  33. data/spec/lib/billy/handlers/proxy_handler_spec.rb +0 -258
  34. data/spec/lib/billy/handlers/request_handler_spec.rb +0 -200
  35. data/spec/lib/billy/handlers/request_log_spec.rb +0 -74
  36. data/spec/lib/billy/handlers/stub_handler_spec.rb +0 -117
  37. data/spec/lib/billy/proxy_connection_spec.rb +0 -20
  38. data/spec/lib/billy/proxy_request_stub_spec.rb +0 -252
  39. data/spec/lib/billy/resource_utils_spec.rb +0 -55
  40. data/spec/lib/billy/ssl/authority_spec.rb +0 -84
  41. data/spec/lib/billy/ssl/certificate_chain_spec.rb +0 -39
  42. data/spec/lib/billy/ssl/certificate_spec.rb +0 -89
  43. data/spec/lib/billy/watir/watir_spec.rb +0 -18
  44. data/spec/lib/proxy_spec.rb +0 -431
  45. data/spec/spec_helper.rb +0 -52
  46. data/spec/support/test_server.rb +0 -79
@@ -1,252 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Billy::ProxyRequestStub do
4
- context '#matches?' do
5
- it 'should match urls and methods' do
6
- expect(Billy::ProxyRequestStub.new('http://example.com')
7
- .matches?('GET', 'http://example.com')).to be
8
- expect(Billy::ProxyRequestStub.new('http://example.com')
9
- .matches?('POST', 'http://example.com')).to_not be
10
-
11
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :get)
12
- .matches?('GET', 'http://example.com')).to be
13
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :post)
14
- .matches?('GET', 'http://example.com')).to_not be
15
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :options)
16
- .matches?('GET', 'http://example.com')).to_not be
17
-
18
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :post)
19
- .matches?('POST', 'http://example.com')).to be
20
- expect(Billy::ProxyRequestStub.new('http://fooxample.com', method: :post)
21
- .matches?('POST', 'http://example.com')).to_not be
22
- expect(Billy::ProxyRequestStub.new('http://fooxample.com', method: :options)
23
- .matches?('POST', 'http://example.com')).to_not be
24
-
25
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :options)
26
- .matches?('OPTIONS', 'http://example.com')).to be
27
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :options)
28
- .matches?('OPTIONS', 'http://zzzzzexample.com')).to_not be
29
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :post)
30
- .matches?('OPTIONS', 'http://example.com')).to_not be
31
- end
32
-
33
- it 'should match regexps' do
34
- expect(Billy::ProxyRequestStub.new(/http:\/\/.+\.com/, method: :post)
35
- .matches?('POST', 'http://example.com')).to be
36
- expect(Billy::ProxyRequestStub.new(/http:\/\/.+\.co\.uk/, method: :get)
37
- .matches?('GET', 'http://example.com')).to_not be
38
- end
39
-
40
- it 'should match up to but not including query strings' do
41
- stub = Billy::ProxyRequestStub.new('http://example.com/foo/bar/')
42
- expect(stub.matches?('GET', 'http://example.com/foo/')).to_not be
43
- expect(stub.matches?('GET', 'http://example.com/foo/bar/')).to be
44
- expect(stub.matches?('GET', 'http://example.com/foo/bar/?baz=bap')).to be
45
- end
46
-
47
- it 'should match all methods' do
48
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :all)
49
- .matches?('GET', 'http://example.com')).to be
50
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :all)
51
- .matches?('POST', 'http://example.com')).to be
52
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :all)
53
- .matches?('OPTIONS', 'http://example.com')).to be
54
- expect(Billy::ProxyRequestStub.new('http://example.com', method: :all)
55
- .matches?('HEAD', 'http://example.com')).to be
56
- end
57
- end
58
-
59
- context "#matches? (with strip_query_params false in config)" do
60
- before do
61
- Billy.config.strip_query_params = false
62
- end
63
-
64
- it 'should not match up to request with query strings' do
65
- stub = Billy::ProxyRequestStub.new('http://example.com/foo/bar/')
66
- expect(stub.matches?('GET', 'http://example.com/foo/')).to_not be
67
- expect(stub.matches?('GET', 'http://example.com/foo/bar/')).to be
68
- expect(stub.matches?('GET', 'http://example.com/foo/bar/?baz=bap')).to_not be
69
- end
70
- end
71
-
72
- context '#call (without #and_return)' do
73
- let(:subject) { Billy::ProxyRequestStub.new('url') }
74
-
75
- it 'returns a 204 empty response' do
76
- expect(subject.call('', '', {}, {}, nil)).to eql [204, { 'Content-Type' => 'text/plain' }, '']
77
- end
78
- end
79
-
80
- context '#and_return + #call' do
81
- let(:subject) { Billy::ProxyRequestStub.new('url') }
82
-
83
- it 'should generate bare responses' do
84
- subject.and_return body: 'baz foo bar'
85
- expect(subject.call('', '', {}, {}, nil)).to eql [
86
- 200,
87
- {},
88
- 'baz foo bar'
89
- ]
90
- end
91
-
92
- it 'should generate text responses' do
93
- subject.and_return text: 'foo bar baz'
94
- expect(subject.call('', '', {}, {}, nil)).to eql [
95
- 200,
96
- { 'Content-Type' => 'text/plain' },
97
- 'foo bar baz'
98
- ]
99
- end
100
-
101
- it 'should generate JSON responses' do
102
- subject.and_return json: { foo: 'bar' }
103
- expect(subject.call('', '', {}, {}, nil)).to eql [
104
- 200,
105
- { 'Content-Type' => 'application/json' },
106
- '{"foo":"bar"}'
107
- ]
108
- end
109
-
110
- context 'JSONP' do
111
- it 'should generate JSONP responses' do
112
- subject.and_return jsonp: { foo: 'bar' }
113
- expect(subject.call('', '', { 'callback' => ['baz'] }, {}, nil)).to eql [
114
- 200,
115
- { 'Content-Type' => 'application/javascript' },
116
- 'baz({"foo":"bar"})'
117
- ]
118
- end
119
-
120
- it 'should generate JSONP responses with custom callback parameter' do
121
- subject.and_return jsonp: { foo: 'bar' }, callback_param: 'cb'
122
- expect(subject.call('', '', { 'cb' => ['bap'] }, {}, nil)).to eql [
123
- 200,
124
- { 'Content-Type' => 'application/javascript' },
125
- 'bap({"foo":"bar"})'
126
- ]
127
- end
128
-
129
- it 'should generate JSONP responses with custom callback name' do
130
- subject.and_return jsonp: { foo: 'bar' }, callback: 'cb'
131
- expect(subject.call('', '', {}, {}, nil)).to eql [
132
- 200,
133
- { 'Content-Type' => 'application/javascript' },
134
- 'cb({"foo":"bar"})'
135
- ]
136
- end
137
- end
138
-
139
- it 'should generate redirection responses' do
140
- subject.and_return redirect_to: 'http://example.com'
141
- expect(subject.call('', '', {}, {}, nil)).to eql [
142
- 302,
143
- { 'Location' => 'http://example.com' },
144
- nil
145
- ]
146
- end
147
-
148
- it 'should set headers' do
149
- subject.and_return text: 'foo', headers: { 'HTTP-X-Foo' => 'bar' }
150
- expect(subject.call('', '', {}, {}, nil)).to eql [
151
- 200,
152
- { 'Content-Type' => 'text/plain', 'HTTP-X-Foo' => 'bar' },
153
- 'foo'
154
- ]
155
- end
156
-
157
- it 'should set status codes' do
158
- subject.and_return text: 'baz', code: 410
159
- expect(subject.call('', '', {}, {}, nil)).to eql [
160
- 410,
161
- { 'Content-Type' => 'text/plain' },
162
- 'baz'
163
- ]
164
- end
165
-
166
- it 'should use a callable' do
167
- expected_params = { 'param1' => ['one'], 'param2' => ['two'] }
168
- expected_headers = { 'header1' => 'three', 'header2' => 'four' }
169
- expected_body = 'body text'
170
-
171
- subject.and_return(proc do |params, headers, body, url, method|
172
- expect(params).to eql expected_params
173
- expect(headers).to eql expected_headers
174
- expect(body).to eql 'body text'
175
- expect(url).to eql 'url'
176
- expect(method).to eql 'GET'
177
- { code: 418, text: 'success' }
178
- end)
179
- expect(subject.call('GET', 'url', expected_params, expected_headers, expected_body)).to eql [
180
- 418,
181
- { 'Content-Type' => 'text/plain' },
182
- 'success'
183
- ]
184
- end
185
-
186
- it 'should use a callable with Billy.pass_request' do
187
- # Add the missing em-synchrony call which is done by
188
- # ProxyConnection#handle_request instead.
189
- EM.synchrony do
190
- subject.and_return(proc do |*args|
191
- response = Billy.pass_request(*args)
192
- response[:body] = 'modified'
193
- response[:code] = 205
194
- response
195
- end)
196
-
197
- # The test server can't be used at this scenario due to the limitations
198
- # of the Ruby GIL. We cannot use fibers (via eventmachine) and ask
199
- # ourself on a different thread to serve a HTTP request. This results
200
- # in +fiber called across threads (FiberError)+ errors. Unfortunately
201
- # we have to ask an external resource.
202
- url = 'http://google.com'
203
-
204
- expect(subject.call('GET', url, {}, {}, 'original')).to eql [
205
- 205,
206
- 'modified'
207
- ]
208
- end
209
- end
210
- end
211
-
212
- context '#stub_requests' do
213
- let(:subject) { Billy::ProxyRequestStub.new('url') }
214
-
215
- before :each do
216
- Billy.config.record_stub_requests = true
217
- end
218
-
219
- it 'should record requests' do
220
- subject.call('', '', {}, {}, nil)
221
- expect(subject.has_requests?).to be true
222
- end
223
-
224
- it 'should record multiple requests' do
225
- expected_amount = 3
226
- expected_amount.times do
227
- subject.call('', '', {}, {}, nil)
228
- end
229
-
230
- expect(subject.requests.length).to eql expected_amount
231
- end
232
-
233
- it 'should set a request' do
234
- expected_request = {
235
- method: 'POST',
236
- url: 'test-url',
237
- params: { 'param1' => ['one'], 'param2' => ['two'] },
238
- headers: { 'header1' => 'three', 'header2' => 'four' },
239
- body: 'body text'
240
- }
241
-
242
- subject.call(
243
- expected_request[:method],
244
- expected_request[:url],
245
- expected_request[:params],
246
- expected_request[:headers],
247
- expected_request[:body]
248
- )
249
- expect(subject.requests[0]).to eql expected_request
250
- end
251
- end
252
- end
@@ -1,55 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Billy::JSONUtils do
4
- describe 'sorting' do
5
- describe '#sort_hash_keys' do
6
- it 'sorts simple Hashes' do
7
- data = { c: 'three', a: 'one', b: 'two' }
8
- expected = { a: 'one', b: 'two', c: 'three' }
9
- expect(Billy::JSONUtils.sort_hash_keys(data)).to eq expected
10
- end
11
-
12
- it 'does not sort simple Arrays' do
13
- data = [3, 1, 2, 'two', 'three', 'one']
14
- expect(Billy::JSONUtils.sort_hash_keys(data)).to eq data
15
- end
16
-
17
- it 'does not sort multi-dimensional Arrays' do
18
- data = [[3, 2, 1], [5, 4, 6], %w(b c a)]
19
- expect(Billy::JSONUtils.sort_hash_keys(data)).to eq data
20
- end
21
-
22
- it 'sorts multi-dimensional Hashes' do
23
- data = { c: { l: 2, m: 3, k: 1 }, a: { f: 3, e: 2, d: 1 }, b: { i: 2, h: 1, j: 3 } }
24
- expected = { a: { d: 1, e: 2, f: 3 }, b: { h: 1, i: 2, j: 3 }, c: { k: 1, l: 2, m: 3 } }
25
- expect(Billy::JSONUtils.sort_hash_keys(data)).to eq expected
26
- end
27
-
28
- it 'sorts abnormal data structures' do
29
- data = { b: [%w(b c a), { ab: 5, aa: 4, ac: 6 }, [3, 2, 1], { ba: true, bc: false, bb: nil }], a: { f: 3, e: 2, d: 1 } }
30
- expected = { a: { d: 1, e: 2, f: 3 }, b: [%w(b c a), { aa: 4, ab: 5, ac: 6 }, [3, 2, 1], { ba: true, bb: nil, bc: false }] }
31
- expect(Billy::JSONUtils.sort_hash_keys(data)).to eq expected
32
- end
33
- end
34
-
35
- describe 'sort_json' do
36
- it 'sorts JSON' do
37
- data = '{"c":"three","a":"one","b":"two"}'
38
- expected = '{"a":"one","b":"two","c":"three"}'
39
- expect(Billy::JSONUtils.sort_json(data)).to eq expected
40
- end
41
- end
42
- end
43
-
44
- describe 'json?' do
45
- let(:json) { { a: '1' }.to_json }
46
- let(:non_json) { 'Not JSON.' }
47
-
48
- it 'identifies JSON' do
49
- expect(Billy::JSONUtils.json?(json)).to be true
50
- end
51
- it 'identifies non-JSON' do
52
- expect(Billy::JSONUtils.json?(non_json)).to be false
53
- end
54
- end
55
- end
@@ -1,84 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Billy::Authority do
4
- let(:auth1) { Billy::Authority.new }
5
- let(:auth2) { Billy::Authority.new }
6
-
7
- context('#key') do
8
- it 'generates a new key each time' do
9
- expect(auth1.key).not_to be(auth2.key)
10
- end
11
-
12
- it 'generates 2048 bit keys' do
13
- expect(auth1.key.n.num_bytes * 8).to be(2048)
14
- end
15
- end
16
-
17
- context('#cert') do
18
- it 'generates a new certificate each time' do
19
- expect(auth1.cert).not_to be(auth2.cert)
20
- end
21
-
22
- it 'generates unique serials' do
23
- expect(auth1.cert.serial).not_to be(auth2.cert.serial)
24
- end
25
-
26
- it 'configures a start date some days ago' do
27
- expect(auth1.cert.not_before).to \
28
- be_between((Date.today - 3).to_time, Date.today.to_time)
29
- end
30
-
31
- it 'configures an end date in some days' do
32
- expect(auth1.cert.not_after).to \
33
- be_between(Date.today.to_time, (Date.today + 3).to_time)
34
- end
35
-
36
- it 'configures the subject' do
37
- expect(auth1.cert.subject.to_s).to \
38
- be_eql('/CN=Puffing Billy/O=Puffing Billy')
39
- end
40
-
41
- it 'configures the certificate authority constrain' do
42
- expect(auth1.cert.extensions.first.to_s).to \
43
- be_eql('basicConstraints = critical, CA:TRUE')
44
- end
45
-
46
- it 'configures SSLv3' do
47
- # Zero-index version numbers. Yay.
48
- expect(auth1.cert.version).to be(2)
49
- end
50
- end
51
-
52
- context('#key_file') do
53
- it 'pass back the path' do
54
- expect(auth1.key_file).to match(/ca.key$/)
55
- end
56
-
57
- it 'creates a temporary file' do
58
- expect(File.exist?(auth1.key_file)).to be(true)
59
- end
60
-
61
- it 'creates a PEM formatted certificate' do
62
- expect(File.read(auth1.key_file)).to match(/^[A-Za-z0-9\-\+\/\=]+$/)
63
- end
64
-
65
- it 'writes out a private key' do
66
- key = OpenSSL::PKey::RSA.new(File.read(auth1.key_file))
67
- expect(key.private?).to be(true)
68
- end
69
- end
70
-
71
- context('#cert_file') do
72
- it 'pass back the path' do
73
- expect(auth1.cert_file).to match(/ca.crt$/)
74
- end
75
-
76
- it 'creates a temporary file' do
77
- expect(File.exist?(auth1.cert_file)).to be(true)
78
- end
79
-
80
- it 'creates a PEM formatted certificate' do
81
- expect(File.read(auth1.cert_file)).to match(/^[A-Za-z0-9\-\+\/\=]+$/)
82
- end
83
- end
84
- end
@@ -1,39 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Billy::CertificateChain do
4
- let(:cert1) { Billy::Certificate.new('localhost') }
5
- let(:cert2) { Billy::Certificate.new('localhost.localdomain') }
6
- let(:chain) do
7
- Billy::CertificateChain.new('localhost', cert1.cert, cert2.cert)
8
- end
9
-
10
- context('#initialize') do
11
- it 'holds all certificates in order' do
12
- expect(chain.certificates).to be_eql([cert1.cert, cert2.cert])
13
- end
14
-
15
- it 'holds the domain' do
16
- expect(chain.domain).to be_eql('localhost')
17
- end
18
- end
19
-
20
- context('#file') do
21
- it 'pass back the path' do
22
- expect(chain.file).to match(/chain-localhost.pem/)
23
- end
24
-
25
- it 'writes out all certificates' do
26
- chain.certificates.each do |cert|
27
- expect(File.read(chain.file)).to include(cert.to_pem)
28
- end
29
- end
30
-
31
- it 'creates a temporary file' do
32
- expect(File.exist?(chain.file)).to be(true)
33
- end
34
-
35
- it 'creates a PEM formatted certificate chain' do
36
- expect(File.read(chain.file)).to match(/^[A-Za-z0-9\-\+\/\=]+$/)
37
- end
38
- end
39
- end
@@ -1,89 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Billy::Certificate do
4
- let(:cert1) { Billy::Certificate.new('localhost') }
5
- let(:cert2) { Billy::Certificate.new('localhost.localdomain') }
6
-
7
- context('#domain') do
8
- it 'holds the domain' do
9
- expect(Billy::Certificate.new('test.tld').domain).to be_eql('test.tld')
10
- end
11
- end
12
-
13
- context('#key') do
14
- it 'generates a new key each time' do
15
- expect(cert1.key).not_to be(cert2.key)
16
- end
17
-
18
- it 'generates 2048 bit keys' do
19
- expect(cert1.key.n.num_bytes * 8).to be(2048)
20
- end
21
- end
22
-
23
- context('#cert') do
24
- it 'generates a new certificate each time' do
25
- expect(cert1.cert).not_to be(cert2.cert)
26
- end
27
-
28
- it 'generates unique serials' do
29
- expect(cert1.cert.serial).not_to be(cert2.cert.serial)
30
- end
31
-
32
- it 'configures a start date some days ago' do
33
- expect(cert1.cert.not_before).to \
34
- be_between((Date.today - 3).to_time, Date.today.to_time)
35
- end
36
-
37
- it 'configures an end date in some days' do
38
- expect(cert1.cert.not_after).to \
39
- be_between(Date.today.to_time, (Date.today + 3).to_time)
40
- end
41
-
42
- it 'configures the correct subject' do
43
- expect(cert1.cert.subject.to_s).to be_eql('/CN=localhost')
44
- end
45
-
46
- it 'configures the subject alternative names' do
47
- expect(cert1.cert.extensions.first.to_s).to \
48
- be_eql('subjectAltName = DNS:localhost')
49
- end
50
-
51
- it 'configures SSLv3' do
52
- # Zero-index version numbers. Yay.
53
- expect(cert1.cert.version).to be(2)
54
- end
55
- end
56
-
57
- context('#key_file') do
58
- it 'pass back the path' do
59
- expect(cert1.key_file).to match(/request-localhost.key$/)
60
- end
61
-
62
- it 'creates a temporary file' do
63
- expect(File.exist?(cert1.key_file)).to be(true)
64
- end
65
-
66
- it 'creates a PEM formatted certificate' do
67
- expect(File.read(cert1.key_file)).to match(/^[A-Za-z0-9\-\+\/\=]+$/)
68
- end
69
-
70
- it 'writes out a private key' do
71
- key = OpenSSL::PKey::RSA.new(File.read(cert1.key_file))
72
- expect(key.private?).to be(true)
73
- end
74
- end
75
-
76
- context('#cert_file') do
77
- it 'pass back the path' do
78
- expect(cert1.cert_file).to match(/request-localhost.crt$/)
79
- end
80
-
81
- it 'creates a temporary file' do
82
- expect(File.exist?(cert1.cert_file)).to be(true)
83
- end
84
-
85
- it 'creates a PEM formatted certificate' do
86
- expect(File.read(cert1.cert_file)).to match(/^[A-Za-z0-9\-\+\/\=]+$/)
87
- end
88
- end
89
- end
@@ -1,18 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Watir-specific tests', type: :feature, js: true do
4
- before do
5
- proxy.stub('http://www.example.com/get').and_return(
6
- text: 'Success!'
7
- )
8
- end
9
-
10
- it 'should raise a NameError if an invalid browser driver is specified' do
11
- expect{Billy::Browsers::Watir.new :invalid}.to raise_error(NameError)
12
- end
13
-
14
- it 'should respond to a stubbed GET request' do
15
- @browser.goto 'http://www.example.com/get'
16
- expect(@browser.text).to eq 'Success!'
17
- end
18
- end