zooming-proxy 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9ce7fec1ef62580c41fd24d84a9831239006d6dc
4
+ data.tar.gz: dd8b3d9f1a65bd359c72dde212b995d00c397e44
5
+ SHA512:
6
+ metadata.gz: 05cb4f51b3b89fd1ab364d0f17bd6656058950daa20f1cd980515a73a107ba4b1439c5f00c816e98f23e771b41672be2f10af88937470fdbbe6e01523f86e4c6
7
+ data.tar.gz: ff528c17789806d933e245ddaa4f1039ce8eff2068059a25ef712e476918444dc7b5d640c1dfb53d9ce770f347db6798f6a97385d501c484d2b67353b49289b7
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ /.bundle/
2
+ /.wercker/
3
+ /pkg/
4
+
5
+ Gemfile.lock
data/.rubocop.yml ADDED
@@ -0,0 +1,8 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.3
3
+
4
+ Metrics/LineLength:
5
+ Max: 100
6
+
7
+ Metrics/MethodLength:
8
+ Max: 15
data/.wercker.yml ADDED
@@ -0,0 +1,11 @@
1
+ box: ruby:2.3
2
+ build:
3
+ steps:
4
+ - bundle-install:
5
+ jobs: "8"
6
+ - script:
7
+ name: cucumber
8
+ code: bundle exec cucumber --color --format pretty --quiet --strict --expand --order random --no-duration --tag ~@wip $CUCUMBER_EXTRA_ARGS
9
+ - script:
10
+ name: rubocop
11
+ code: bundle exec rubocop --display-cop-names --extra-details --display-style-guide
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at jean@blendle.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+ source 'https://rubygems.org'
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Blendle
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # ZoomingProxy [![wercker status](https://app.wercker.com/status/adedcc914bade602a6114105359d3083/s/master "wercker status")](https://app.wercker.com/project/bykey/adedcc914bade602a6114105359d3083)
2
+
3
+ Rack middleware implementing the [zooming-proxy spec][spec]
4
+
5
+ * [Installation](#installation)
6
+ * [Quick Start](#quick-start)
7
+ * [License](#license)
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'zooming-proxy'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ ```shell
20
+ bundle
21
+ ```
22
+
23
+ Or install it yourself as:
24
+
25
+ ```shell
26
+ gem install zooming-proxy
27
+ ```
28
+
29
+ ## Quick Start
30
+
31
+ ```ruby
32
+ # require the proper libraries in your project
33
+ require 'zooming-proxy'
34
+
35
+ # enable the middleware in your `config.ru`
36
+ use ZoomingProxy::Middleware
37
+
38
+ # make a request, to see if things work as expected
39
+ curl -sI 'https://example.org/hello/world' | grep 'X-HAL-Zoomed'
40
+ # => X-HAL-Zoomed: 1
41
+ ```
42
+
43
+ ## License
44
+
45
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
46
+
47
+ [spec]: https://github.com/blendle/zoomingproxy-spec
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'cucumber/rake/task'
5
+ require 'rake/testtask'
6
+ require 'rubocop/rake_task'
7
+
8
+ RuboCop::RakeTask.new do |t|
9
+ t.options = %w(--display-cop-names --extra-details --display-style-guide)
10
+ end
11
+
12
+ Cucumber::Rake::Task.new(:features) do |t|
13
+ t.cucumber_opts = 'features --order random --no-multiline --no-snippets --no-source'
14
+ end
15
+
16
+ task default: %i(features rubocop)
@@ -0,0 +1,4 @@
1
+ # rubocop:disable Style/FileName
2
+ # frozen_string_literal: true
3
+
4
+ require 'zooming-proxy/middleware'
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module ZoomingProxy
6
+ # Middleware
7
+ #
8
+ class Middleware
9
+ attr_reader :host, :scheme, :forwarded
10
+
11
+ MAX_DEPTH = 10
12
+
13
+ def initialize(app)
14
+ @app = app
15
+ end
16
+
17
+ def call(env)
18
+ @host = env['SERVER_NAME']
19
+ @scheme = env['rack.url_scheme']
20
+ @forwarded = env['REMOTE_ADDR']
21
+ @encoding = env['HTTP_ACCEPT_ENCODING']
22
+
23
+ handle_response(*@app.call(env))
24
+ end
25
+
26
+ private
27
+
28
+ def handle_response(status, headers, response)
29
+ proxy_headers = headers.dup
30
+ proxy_headers['X-Forwarded-For'] = forwarded
31
+ proxy_headers['X-HAL-Zooming'] = '0'
32
+
33
+ proxy_headers.delete('Accept-Encoding')
34
+
35
+ compress embed(status, proxy_headers, response)
36
+ end
37
+
38
+ def compress(response)
39
+ return response unless @encoding.to_s.include?('gzip')
40
+
41
+ response[2][0] = string_to_gzip(response[2][0])
42
+ response[1]['Content-Encoding'] = 'gzip'
43
+ response[1]['Content-Length'] = response[2][0].bytesize
44
+
45
+ response
46
+ end
47
+
48
+ def string_to_gzip(source)
49
+ output = StringIO.new
50
+ gz = Zlib::GzipWriter.new(output)
51
+ gz.write(source)
52
+ gz.close
53
+ output.string
54
+ end
55
+
56
+ def embed(status, headers, response, depth: 1)
57
+ body = response_to_hash(response)
58
+ return zoomed_response(status, headers, body, depth) unless zoomable?(headers, body, depth)
59
+
60
+ body['_embedded'] ||= {}
61
+ headers['X-HAL-Zooming'] = depth
62
+
63
+ requested_links(body, headers).each { |link| body = zoom_rel(headers, body, depth, link) }
64
+ zoomed_response(status, headers, body, depth)
65
+ end
66
+
67
+ def zoom_rel(headers, body, depth, link)
68
+ relation, hrefs = link
69
+ array = hrefs.respond_to?(:to_ary)
70
+
71
+ [*hrefs].each do |href|
72
+ res = request_rel(href, headers)
73
+ embedded_body = handle_nested_embeds(res, depth)
74
+
75
+ if array
76
+ body['_embedded'][relation] ||= []
77
+ body['_embedded'][relation] << embedded_body
78
+ else
79
+ body['_embedded'][relation] = embedded_body
80
+ end
81
+ end
82
+
83
+ body
84
+ end
85
+
86
+ def request_rel(href, headers)
87
+ uri = URI.parse(href)
88
+ uri.scheme = scheme
89
+ uri.host = host
90
+
91
+ Typhoeus.get(uri, headers: headers)
92
+ end
93
+
94
+ def response_to_hash(response)
95
+ response = response.to_json if response.respond_to?(:each_key)
96
+
97
+ JSON.parse(body_from_rack_response(response))
98
+ rescue JSON::ParserError
99
+ nil
100
+ end
101
+
102
+ def handle_nested_embeds(res, depth)
103
+ _, _, response = embed(res.code, res.headers, res.body, depth: depth + 1)
104
+ response_to_hash(response)
105
+ end
106
+
107
+ def body_from_rack_response(response)
108
+ [*response].join
109
+ end
110
+
111
+ def zoomed_response(status, headers, body, depth)
112
+ json = body.to_json
113
+
114
+ headers['Content-Length'] = json.bytesize
115
+ headers['X-HAL-Zoomed'] = depth.to_s
116
+
117
+ [status, headers, [json]]
118
+ end
119
+
120
+ def zoomable?(headers, body, depth)
121
+ zoomable = depth <= MAX_DEPTH
122
+ zoomable &= headers.include?('x-hal-zoom')
123
+ zoomable &= headers['content-type'].include?('json')
124
+
125
+ zoomable && !body.nil?
126
+ end
127
+
128
+ def requested_links(body, headers)
129
+ links = requested_zooms(headers).select { |rel| body['_links'].key?(rel) }
130
+ links.map do |rel|
131
+ link = body['_links'][rel]
132
+
133
+ [rel, link.respond_to?(:to_ary) ? link.map { |l| l['href'] } : link['href']]
134
+ end
135
+ end
136
+
137
+ def requested_zooms(headers)
138
+ headers['x-hal-zoom'].split(/\s+/)
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ZoomingProxy
4
+ VERSION = '0.1.0'
5
+ end
data/script/test ADDED
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ docker-compose run spec bundle exec cucumber "$@"
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'zooming-proxy/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'zooming-proxy'
9
+ spec.version = ZoomingProxy::VERSION
10
+ spec.authors = ['Blendle developers']
11
+ spec.email = ['support@blendle.com']
12
+
13
+ spec.summary = 'Rack middleware to simulate the "zooming proxy" spec'
14
+ spec.description = 'Using this Rack middleware Gem, you can zoom requests.'
15
+ spec.homepage = 'https://blendle.com'
16
+ spec.license = 'MIT'
17
+ spec.require_paths = ['lib']
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ .reject { |f| f.match(%r{^(test|spec|features)/}) }
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.12'
22
+ spec.add_development_dependency 'cucumber', '~> 2.4'
23
+ spec.add_development_dependency 'cucumber-blendle-steps', '~> 0.8'
24
+ spec.add_development_dependency 'json', '~> 1.8'
25
+ spec.add_development_dependency 'json_spec', '~> 1.1'
26
+ spec.add_development_dependency 'minitest', '~> 5.0'
27
+ spec.add_development_dependency 'pry', '~> 0.10'
28
+ spec.add_development_dependency 'rack-test', '~> 0.6'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+ spec.add_development_dependency 'rubocop', '~> 0.40'
31
+ spec.add_development_dependency 'sinatra', '~> 1.4'
32
+ spec.add_development_dependency 'webmock', '~> 2.0'
33
+ end
metadata ADDED
@@ -0,0 +1,225 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zooming-proxy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Blendle developers
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-06-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: cucumber
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.4'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: cucumber-blendle-steps
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.8'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: json
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.8'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.8'
69
+ - !ruby/object:Gem::Dependency
70
+ name: json_spec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.1'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '5.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '5.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.10'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.10'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rack-test
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.6'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.6'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rake
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '10.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '10.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.40'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.40'
153
+ - !ruby/object:Gem::Dependency
154
+ name: sinatra
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '1.4'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '1.4'
167
+ - !ruby/object:Gem::Dependency
168
+ name: webmock
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '2.0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '2.0'
181
+ description: Using this Rack middleware Gem, you can zoom requests.
182
+ email:
183
+ - support@blendle.com
184
+ executables: []
185
+ extensions: []
186
+ extra_rdoc_files: []
187
+ files:
188
+ - ".gitignore"
189
+ - ".rubocop.yml"
190
+ - ".wercker.yml"
191
+ - CODE_OF_CONDUCT.md
192
+ - Gemfile
193
+ - LICENSE.txt
194
+ - README.md
195
+ - Rakefile
196
+ - lib/zooming-proxy.rb
197
+ - lib/zooming-proxy/middleware.rb
198
+ - lib/zooming-proxy/version.rb
199
+ - script/test
200
+ - zooming-proxy.gemspec
201
+ homepage: https://blendle.com
202
+ licenses:
203
+ - MIT
204
+ metadata: {}
205
+ post_install_message:
206
+ rdoc_options: []
207
+ require_paths:
208
+ - lib
209
+ required_ruby_version: !ruby/object:Gem::Requirement
210
+ requirements:
211
+ - - ">="
212
+ - !ruby/object:Gem::Version
213
+ version: '0'
214
+ required_rubygems_version: !ruby/object:Gem::Requirement
215
+ requirements:
216
+ - - ">="
217
+ - !ruby/object:Gem::Version
218
+ version: '0'
219
+ requirements: []
220
+ rubyforge_project:
221
+ rubygems_version: 2.6.4
222
+ signing_key:
223
+ specification_version: 4
224
+ summary: Rack middleware to simulate the "zooming proxy" spec
225
+ test_files: []