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,15 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'jQuery POST API example', type: :feature, js: true do
4
- before do
5
- proxy.stub('http://example.com/api', method: 'post').and_return(
6
- headers: { 'Access-Control-Allow-Origin' => '*' },
7
- code: 201
8
- )
9
- end
10
-
11
- it 'posts to an API' do
12
- visit '/post_api.html'
13
- expect(page.find('#result')).to have_content 'Success!'
14
- end
15
- end
@@ -1,29 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'jQuery preflight request example', type: :feature, js: true do
4
- let(:url) { 'http://example.com/api' }
5
-
6
- before do
7
- proxy.stub(url, method: 'get').and_return(
8
- headers: { 'Access-Control-Allow-Origin' => '*' },
9
- code: 201
10
- )
11
- end
12
-
13
- it 'stubs out the OPTIONS request' do
14
- visit '/preflight_request.html'
15
- expect(page.find('#result')).to have_content 'Fail!'
16
-
17
- proxy.stub(url, method: 'options').and_return(
18
- headers: {
19
- 'Access-Control-Allow-Methods' => 'GET, OPTIONS',
20
- 'Access-Control-Allow-Headers' => 'Content-Type',
21
- 'Access-Control-Allow-Origin' => '*'
22
- },
23
- code: 200
24
- )
25
-
26
- visit '/preflight_request.html'
27
- expect(page.find('#result')).to have_content 'Success!'
28
- end
29
- end
@@ -1,59 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.shared_examples 'tumblr/expectations' do
4
- it 'should show news stories' do
5
- visit '/tumblr_api.html'
6
- expect(page).to have_link('News Item 1', href: 'http://example.com/news/1')
7
- expect(page).to have_content('News item 1 content here')
8
- expect(page).to have_link('News Item 2', href: 'http://example.com/news/2')
9
- expect(page).to have_content('News item 2 content here')
10
- end
11
- end
12
-
13
- describe 'Tumblr API example', type: :feature, js: true do
14
- context 'without scope external references' do
15
- before do
16
- proxy.stub('http://blog.howmanyleft.co.uk/api/read/json').and_return(
17
- jsonp: {
18
- posts: [
19
- {
20
- 'regular-title' => 'News Item 1',
21
- 'url-with-slug' => 'http://example.com/news/1',
22
- 'regular-body' => 'News item 1 content here'
23
- },
24
- {
25
- 'regular-title' => 'News Item 2',
26
- 'url-with-slug' => 'http://example.com/news/2',
27
- 'regular-body' => 'News item 2 content here'
28
- }
29
- ]
30
- })
31
- end
32
-
33
- include_examples 'tumblr/expectations'
34
- end
35
-
36
- context 'with scope external references' do
37
- let(:posts) do
38
- [
39
- {
40
- 'regular-title' => 'News Item 1',
41
- 'url-with-slug' => 'http://example.com/news/1',
42
- 'regular-body' => 'News item 1 content here'
43
- },
44
- {
45
- 'regular-title' => 'News Item 2',
46
- 'url-with-slug' => 'http://example.com/news/2',
47
- 'regular-body' => 'News item 2 content here'
48
- }
49
- ]
50
- end
51
-
52
- before do
53
- proxy.stub('http://blog.howmanyleft.co.uk/api/read/json')
54
- .and_return(proc { { jsonp: { posts: posts } } })
55
- end
56
-
57
- include_examples 'tumblr/expectations'
58
- end
59
- end
@@ -1,28 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Capybara drivers', type: :feature, js: true do
4
- it 'allows HTTPS calls' do
5
- proxy.stub('https://blog.howmanyleft.co.uk:443/api/read/json').and_return(
6
- jsonp: {
7
- posts: [
8
- {
9
- 'regular-title' => 'News Item 1',
10
- 'url-with-slug' => 'http://example.com/news/1',
11
- 'regular-body' => 'News item 1 content here'
12
- },
13
- {
14
- 'regular-title' => 'News Item 2',
15
- 'url-with-slug' => 'http://example.com/news/2',
16
- 'regular-body' => 'News item 2 content here'
17
- }
18
- ]
19
- })
20
-
21
- visit '/tumblr_api_https.html'
22
-
23
- expect(page).to have_link('News Item 1', href: 'http://example.com/news/1')
24
- expect(page).to have_content('News item 1 content here')
25
- expect(page).to have_link('News Item 2', href: 'http://example.com/news/2')
26
- expect(page).to have_content('News item 2 content here')
27
- end
28
- end
@@ -1,158 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Billy::Cache do
4
- let(:cache) { Billy::Cache.instance }
5
- let(:params) { '?foo=bar' }
6
- let(:callback) { '&callback=quux' }
7
- let(:fragment) { '#baz' }
8
- let(:base_url) { 'http://example.com' }
9
- let(:pipe_url) { 'https://fonts.googleapis.com:443/css?family=Cabin+Sketch:400,700|Love+Ya+Like+A+Sister' }
10
- let(:fragment_url) { "#{base_url}/#{fragment}" }
11
- let(:params_url) { "#{base_url}#{params}" }
12
- let(:params_url_with_callback) { "#{base_url}#{params}#{callback}" }
13
- let(:params_fragment_url) { "#{base_url}#{params}#{fragment}" }
14
-
15
- describe 'format_url' do
16
- context 'with ignore_params set to false' do
17
- it 'is a no-op if there are no params' do
18
- expect(cache.format_url(base_url)).to eq base_url
19
- end
20
- it 'appends params if there are params' do
21
- expect(cache.format_url(params_url)).to eq params_url
22
- end
23
- it 'appends params and fragment if both are present' do
24
- expect(cache.format_url(params_fragment_url)).to eq params_fragment_url
25
- end
26
- it 'does not raise error for URLs with pipes' do
27
- expect { cache.format_url(pipe_url) }.not_to raise_error
28
- end
29
-
30
- context 'when dynamic_jsonp is true' do
31
- it 'omits the callback param by default' do
32
- expect(cache.format_url(params_url_with_callback, false, true)).to eq params_url
33
- end
34
-
35
- it 'omits the params listed in Billy.config.dynamic_jsonp_keys' do
36
- allow(Billy.config).to receive(:dynamic_jsonp_keys) { ['foo'] }
37
-
38
- expect(cache.format_url(params_url_with_callback, false, true)).to eq "#{base_url}?callback=quux"
39
- end
40
- end
41
-
42
- it 'retains the callback param is dynamic_jsonp is false' do
43
- expect(cache.format_url(params_url_with_callback)).to eq params_url_with_callback
44
- end
45
- end
46
-
47
- context 'with ignore_params set to true' do
48
- it 'is a no-op if there are no params' do
49
- expect(cache.format_url(base_url, true)).to eq base_url
50
- end
51
- it 'omits params if there are params' do
52
- expect(cache.format_url(params_url, true)).to eq base_url
53
- end
54
- it 'omits params and fragment if both are present' do
55
- expect(cache.format_url(params_fragment_url, true)).to eq base_url
56
- end
57
- end
58
-
59
- context 'with merge_cached_responses_whitelist set' do
60
- let(:analytics_url1) { 'http://www.example-analytics.com/user/SDF879932/' }
61
- let(:analytics_url2) { 'http://www.example-analytics.com/user/OIWEMLW39/' }
62
- let(:regular_url) { 'http://www.example-analytics.com/user.js' }
63
-
64
- let(:regex_to_match_analytics_urls_only) do
65
- # Note that it matches the forward slash at the end of the URL, which doesn't match regular_url:
66
- /www\.example\-analytics\.com\/user\//
67
- end
68
-
69
- before do
70
- allow(Billy.config).to receive(:merge_cached_responses_whitelist) {
71
- [regex_to_match_analytics_urls_only]
72
- }
73
- end
74
-
75
- it "has one cache key for the two analytics urls that match, and a separate one for the other that doesn't" do
76
- expect(cache.key('post', analytics_url1, 'body')).to eq cache.key('post', analytics_url2, 'body')
77
- expect(cache.key('post', analytics_url1, 'body')).not_to eq cache.key('post', regular_url, 'body')
78
- end
79
-
80
- it 'More specifically, the cache keys should be identical for the 2 analytics urls' do
81
- identical_cache_key = 'post_5fcb7a450e4cd54dcffcb526212757ee0ca9dc17'
82
- distinct_cache_key = 'post_www.example-analytics.com_81f097654a523bd7ddb10fd4aee781723e076a1a_02083f4579e08a612425c0c1a17ee47add783b94'
83
-
84
- expect(cache.key('post', analytics_url1, 'body')).to eq identical_cache_key
85
- expect(cache.key('post', regular_url, 'body')).to eq distinct_cache_key
86
- expect(cache.key('post', analytics_url2, 'body')).to eq identical_cache_key
87
- end
88
- end
89
-
90
- context 'with cache_request_body_methods set' do
91
- before do
92
- allow(Billy.config).to receive(:cache_request_body_methods) {
93
- ['patch']
94
- }
95
- end
96
-
97
- context "for requests with methods specified in cache_request_body_methods" do
98
- it "should have a different cache key for requests with different bodies" do
99
- key1 = cache.key('patch', "http://example.com", "body1")
100
- key2 = cache.key('patch', "http://example.com", "body2")
101
- expect(key1).not_to eq key2
102
- end
103
-
104
- it "should have the same cache key for requests with the same bodies" do
105
- key1 = cache.key('patch', "http://example.com", "body1")
106
- key2 = cache.key('patch', "http://example.com", "body1")
107
- expect(key1).to eq key2
108
- end
109
- end
110
-
111
- it "should have the same cache key for request with different bodies if their methods are not included in cache_request_body_methods" do
112
- key1 = cache.key('put', "http://example.com", "body1")
113
- key2 = cache.key('put', "http://example.com", "body2")
114
- expect(key1).to eq key2
115
- end
116
- end
117
- end
118
-
119
- describe 'key' do
120
- context 'with use_ignore_params set to false' do
121
- before do
122
- allow(Billy.config).to receive(:use_ignore_params) { false }
123
- end
124
-
125
- it "should use the same cache key if the base url IS NOT whitelisted in allow_params" do
126
- key1 = cache.key('put', params_url, 'body')
127
- key2 = cache.key('put', params_url, 'body')
128
- expect(key1).to eq key2
129
- end
130
-
131
- it "should have the same cache key if the base IS whitelisted in allow_params" do
132
- allow(Billy.config).to receive(:allow_params) { [base_url] }
133
- key1 = cache.key('put', params_url, 'body')
134
- key2 = cache.key('put', params_url, 'body')
135
- expect(key1).to eq key2
136
- end
137
-
138
- it "should have different cache keys if the base url is added in between two requests" do
139
- key1 = cache.key('put', params_url, 'body')
140
- allow(Billy.config).to receive(:allow_params) { [base_url] }
141
- key2 = cache.key('put', params_url, 'body')
142
- expect(key1).not_to eq key2
143
- end
144
-
145
- it "should not use ignore_params when whitelisted" do
146
- allow(Billy.config).to receive(:allow_params) { [base_url] }
147
- expect(cache).to receive(:format_url).once.with(params_url, true).and_call_original
148
- expect(cache).to receive(:format_url).once.with(params_url, false).and_call_original
149
- key1 = cache.key('put', params_url, 'body')
150
- end
151
-
152
- it "should use ignore_params when not whitelisted" do
153
- expect(cache).to receive(:format_url).twice.with(params_url, true).and_call_original
154
- cache.key('put', params_url, 'body')
155
- end
156
- end
157
- end
158
- end
@@ -1,191 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Billy::CacheHandler do
4
- let(:handler) { Billy::CacheHandler.new }
5
- let(:request_url) { 'http://example.test:8080/index?some=param&callback=dynamicCallback5678' }
6
- let(:request) do
7
- {
8
- method: 'post',
9
- url: request_url,
10
- headers: { 'Accept-Encoding' => 'gzip',
11
- 'Cache-Control' => 'no-cache' },
12
- body: 'Some body'
13
- }
14
- end
15
-
16
- it 'delegates #reset to the cache' do
17
- expect(Billy::Cache.instance).to receive(:reset).at_least(:once)
18
- handler.reset
19
- end
20
-
21
- it 'delegates #cached? to the cache' do
22
- expect(Billy::Cache.instance).to receive :cached?
23
- handler.cached?
24
- end
25
-
26
- describe '#handles_request?' do
27
- it 'handles the request if it is cached' do
28
- expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
29
- expect(handler.handles_request?(nil, nil, nil, nil)).to be true
30
- end
31
-
32
- it 'does not handle the request if it is not cached' do
33
- expect(Billy::Cache.instance).to receive(:cached?).and_return(false)
34
- expect(handler.handles_request?(nil, nil, nil, nil)).to be false
35
- end
36
- end
37
-
38
- describe '#handle_request' do
39
- it 'returns nil if the request cannot be handled' do
40
- expect(Billy::Cache.instance).to receive(:cached?).and_return(false)
41
- expect(handler.handle_request(request[:method],
42
- request[:url],
43
- request[:headers],
44
- request[:body])).to be nil
45
- end
46
-
47
- it 'returns a cached response if the request can be handled' do
48
- expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
49
- expect(Billy::Cache.instance).to receive(:fetch).and_return(status: 200, headers: { 'Connection' => 'close' }, content: 'The response body')
50
- expect(handler.handle_request(request[:method],
51
- request[:url],
52
- request[:headers],
53
- request[:body])).to eql(status: 200, headers: { 'Connection' => 'close' }, content: 'The response body')
54
- end
55
-
56
- context 'updating jsonp callback names enabled' do
57
- before do
58
- Billy.config.dynamic_jsonp = true
59
- end
60
-
61
- it 'updates the cached response if the callback is dynamic' do
62
- expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
63
- expect(Billy::Cache.instance).to receive(:fetch).and_return(status: 200, headers: { 'Connection' => 'close' }, content: 'dynamicCallback1234({"yolo":"kitten"})')
64
- expect(handler.handle_request(request[:method],
65
- request[:url],
66
- request[:headers],
67
- request[:body])).to eql(status: 200, headers: { 'Connection' => 'close' }, content: 'dynamicCallback5678({"yolo":"kitten"})')
68
- end
69
-
70
- it 'is flexible about the format of the response body' do
71
- expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
72
- expect(Billy::Cache.instance).to receive(:fetch).and_return(status: 200, headers: { 'Connection' => 'close' }, content: "/**/ dynamicCallback1234(\n{\"yolo\":\"kitten\"})")
73
- expect(handler.handle_request(request[:method],
74
- request[:url],
75
- request[:headers],
76
- request[:body])).to eql(status: 200, headers: { 'Connection' => 'close' }, content: "/**/ dynamicCallback5678(\n{\"yolo\":\"kitten\"})")
77
- end
78
-
79
- it 'does not interfere with non-jsonp requests' do
80
- jsonp_request = request
81
- other_request = {
82
- method: 'get',
83
- url: 'http://example.test:8080/index?hanukkah=latkes',
84
- headers: { 'Accept-Encoding' => 'gzip', 'Cache-Control' => 'no-cache' },
85
- body: 'no jsonp'
86
- }
87
-
88
- allow(Billy::Cache.instance).to receive(:cached?).and_return(true)
89
- allow(Billy::Cache.instance).to receive(:fetch).with(jsonp_request[:method], jsonp_request[:url], jsonp_request[:body]).and_return(status: 200,
90
- headers: { 'Connection' => 'close' },
91
- content: 'dynamicCallback1234({"yolo":"kitten"})')
92
- allow(Billy::Cache.instance).to receive(:fetch).with(other_request[:method], other_request[:url], other_request[:body]).and_return(status: 200,
93
- headers: { 'Connection' => 'close' },
94
- content: 'no jsonp but has parentheses()')
95
-
96
- expect(handler.handle_request(other_request[:method],
97
- other_request[:url],
98
- other_request[:headers],
99
- other_request[:body])).to eql(status: 200, headers: { 'Connection' => 'close' }, content: 'no jsonp but has parentheses()')
100
- end
101
-
102
- context 'when after_cache_handles_request is set' do
103
- it "should call the callback with the request and response" do
104
- allow(Billy.config).to receive(:after_cache_handles_request) do
105
- proc do |request, response|
106
- response[:headers]['Access-Control-Allow-Origin'] = "*"
107
- response[:content] = request[:body]
108
- end
109
- end
110
- expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
111
- expect(Billy::Cache.instance).to receive(:fetch).and_return(status: 200, headers: { 'Connection' => 'close' }, content: 'The response body')
112
- expect(handler.handle_request(request[:method],
113
- request[:url],
114
- request[:headers],
115
- request[:body])).to eql(status: 200, headers: { 'Connection' => 'close', 'Access-Control-Allow-Origin' => "*" }, content: 'Some body')
116
- end
117
- end
118
-
119
- context 'when dynamic_jsonp_callback_name is set' do
120
- let(:dynamic_jsonp_callback_name) { 'customCallback' }
121
- let(:request_url) { "http://example.test:8080/index?some=param&#{dynamic_jsonp_callback_name}=dynamicCallback5678" }
122
-
123
- before do
124
- allow(Billy.config).to receive(:dynamic_jsonp_callback_name) do
125
- dynamic_jsonp_callback_name
126
- end
127
- end
128
-
129
- it 'should call the callback with the specified name' do
130
- expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
131
- expect(Billy::Cache.instance).to receive(:fetch).and_return(status: 200, headers: { 'Connection' => 'close' }, content: 'dynamicCallback1234({"yolo":"kitten"})')
132
- expect(handler.handle_request(request[:method],
133
- request[:url],
134
- request[:headers],
135
- request[:body])).to eql(status: 200, headers: { 'Connection' => 'close' }, content: 'dynamicCallback5678({"yolo":"kitten"})')
136
- end
137
- end
138
- end
139
-
140
- context 'updating jsonp callback names disabled' do
141
- before do
142
- Billy.config.dynamic_jsonp = false
143
- end
144
-
145
- it 'does not change the response' do
146
- expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
147
- expect(Billy::Cache.instance).to receive(:fetch).and_return(status: 200, headers: { 'Connection' => 'close' }, content: 'dynamicCallback1234({"yolo":"kitten"})')
148
- expect(handler.handle_request(request[:method],
149
- request[:url],
150
- request[:headers],
151
- request[:body])).to eql(status: 200, headers: { 'Connection' => 'close' }, content: 'dynamicCallback1234({"yolo":"kitten"})')
152
- end
153
- end
154
-
155
- it 'returns nil if the Cache fails to handle the response for some reason' do
156
- expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
157
- expect(Billy::Cache.instance).to receive(:fetch).and_return(nil)
158
- expect(handler.handle_request(request[:method],
159
- request[:url],
160
- request[:headers],
161
- request[:body])).to be nil
162
- end
163
-
164
- context 'network delay simulation' do
165
- before do
166
- allow(Billy::Cache.instance).to receive(:cached?).and_return(true)
167
- allow(Billy::Cache.instance).to receive(:fetch).and_return(status: 200, headers: { 'Connection' => 'close' }, content: 'dynamicCallback1234({"yolo":"kitten"})')
168
- end
169
-
170
- context 'when cache_simulates_network_delays is disabled' do
171
- it 'does not sleep for default delay before responding' do
172
- expect(Kernel).not_to receive(:sleep)
173
- handler.handle_request(request[:method], request[:url], request[:headers], request[:body])
174
- end
175
- end
176
-
177
- context 'when cache_simulates_network_delays is enabled' do
178
- around do |example|
179
- Billy.config.cache_simulates_network_delays = true
180
- example.call
181
- Billy.config.cache_simulates_network_delays = false
182
- end
183
-
184
- it 'sleeps for default delay before responding' do
185
- expect(Kernel).to receive(:sleep).with(Billy.config.cache_simulates_network_delay_time)
186
- handler.handle_request(request[:method], request[:url], request[:headers], request[:body])
187
- end
188
- end
189
- end
190
- end
191
- end
@@ -1,16 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Billy::Handler do
4
- let(:handler) { Class.new { include Billy::Handler }.new }
5
- it '#handle_request raises an error if not overridden' do
6
- expect(handler.handle_request(nil, nil, nil, nil)).to eql(error: 'The handler has not overridden the handle_request method!')
7
- end
8
-
9
- it '#handles_request returns false by default' do
10
- expect(handler.handles_request?(nil, nil, nil, nil)).to be false
11
- end
12
-
13
- it 'responds to #reset' do
14
- expect(handler).to respond_to :reset
15
- end
16
- end