service-proxy 0.2.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: faf306e26c813332a695bf550b707d53f4c489f213e46e2dd4b658904781587e
4
+ data.tar.gz: dcdde7dbaf1031b60d8cb358678579eba7831c9f25126f3a128f1985a5e83df6
5
+ SHA512:
6
+ metadata.gz: c58f05067a4aa1dd313ddebf14154c1c508fce79b4d21a270e0cb92893e44dc8f88a302b4113fb87df9b5ca0191eddb00a588563207434ed6606111a460667e1
7
+ data.tar.gz: '0256529216e31016783b0fa0c4e2645c1044160e59a331dc150d336fd92362b05abe6cd1cfcae4f2cd512eba26af89245708ddcb24a52df4681142d0683f9663'
@@ -0,0 +1,20 @@
1
+ Copyright 2020 Donald Piret
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,75 @@
1
+ # Service::Proxy
2
+
3
+ When running a service-oriented architecture, it is sometimes desirable to allow your backend services to be mapped to URL paths within the application itself.
4
+
5
+ This allows you for example to be able to share cookies and reduce the need for CORS calls or to expose your services in a way that they are accessible only through a particular front-end application.
6
+
7
+ This gem allows you to easily set up these backend service proxy's through a simple YAML configuration file.
8
+
9
+ ## Installation
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+
14
+ source "https://rubygems.pkg.github.com/sephora-asia" do
15
+ gem 'service-proxy'
16
+ end
17
+
18
+ ```
19
+
20
+ And then execute:
21
+ ```bash
22
+ $ bundle
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ Create a file named ``config/service_proxy.yml`` in your rails application directory. It should look something like this -
28
+
29
+ ```yml
30
+ default: &default
31
+ services:
32
+ address-api:
33
+ path: /api/address
34
+ backend: https://www.my-address-api.com:8888/
35
+
36
+ user-api:
37
+ path: /api/user
38
+ backend: https://www.my-user-api.com/
39
+
40
+ rewards-api:
41
+ path: /api/rewards
42
+ backend: http://www.my-rewards-api.com:9999/
43
+
44
+ ads-api:
45
+ path: /api/ads
46
+ backend: http://www.my-ads-api.com:1101/
47
+ forward_cookies: false
48
+
49
+
50
+ development:
51
+ <<: *default
52
+
53
+ test:
54
+ <<: *default
55
+ ```
56
+
57
+ Each of the `services` block sequence in the `yml` file is given a - `sequence name`, and are expected to contain `path` and `backend` scalar. The request url that the app receives will be matched against each of these `path` and if a match is found, then the request will be forwarded to the corresponding backend. For eg. based on the above config, if our app is responding to https://www.my-app.com, then if a request to https://www.my-app.com/api/rewards?reward_id=1234 is made, it will be matched against the `rewards-api` block sequence and the same request will get forwarded as http://www.my-rewards-api.com:9999/?reward_id=1234.
58
+
59
+ Each block sequence can contain the following scalars -
60
+ - `path` : The path that needs to be matched in the request url. It is a required field.
61
+ - `backend` : This is the destination URI that we need to forward the current request to. This needs to have a valid url scheme `[scheme]://[domain]:[port]/`. Supported `scheme` is either `http` or `https`. `port` is optional and the default value of 80 or 443 is used depending up on whether the scheme is `http` or `https`. This is also a required field.
62
+ - `forward_cookies`: Can be `true` (default value) or `false`. Cookies will not be forwarded to `backend` if this is set to false.
63
+ - `read_timeout`: This sets the proxy timeout. By default it times out in 60 seconds.
64
+ - `verify_ssl`: Can be `true` (default value) or `false`. This tells `Net::HTTP` to not validate certs if set to `false`.
65
+
66
+ ## Contributing
67
+
68
+ Run `make setup` in order to install your dev environment.
69
+
70
+ This project uses the [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) for commit naming.
71
+
72
+ Publishing is done automatically when a push to the master branch is detected.
73
+
74
+ ## License
75
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,17 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Service::Proxy'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ require 'bundler/gem_tasks'
@@ -0,0 +1,5 @@
1
+ require 'service/proxy/version'
2
+ require 'service/proxy/config'
3
+ require 'service/proxy/middleware'
4
+ require 'service/proxy/service_config'
5
+ require 'service/proxy/railtie' if defined?(Rails)
@@ -0,0 +1,23 @@
1
+ module Service
2
+ module Proxy
3
+ class Config
4
+ attr_reader :config
5
+
6
+ def initialize(config = {})
7
+ @config = config || {}
8
+ end
9
+
10
+ def proxied_paths_matcher
11
+ @proxied_paths_matcher ||= Regexp.union(services.collect(&:path_regexp))
12
+ end
13
+
14
+ def service_matching_path(path)
15
+ services.detect { |service| service.path_regexp =~ path }
16
+ end
17
+
18
+ def services
19
+ @services ||= config.fetch(:services, {}).map { |k, v| ServiceConfig.new(k, v) }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rack-proxy'
4
+
5
+ module Service
6
+ module Proxy
7
+ class Middleware < Rack::Proxy
8
+ def perform_request(env)
9
+ request = Rack::Request.new(env)
10
+
11
+ # use rack proxy for anything hitting our host app at /example_service
12
+ if config && request.path =~ config.proxied_paths_matcher
13
+ service = config.service_matching_path(request.path)
14
+
15
+ # most backends required host set properly, but rack-proxy doesn't set this for you automatically
16
+ # even when a backend host is passed in via the options
17
+ env['SERVER_NAME'] = env['HTTP_HOST'] = [service.backend.host, service.backend.port].compact.join(':')
18
+ env['SERVER_PORT'] = service.backend.port.to_s
19
+ env['rack.backend'] = service.backend
20
+ env['rack.url_scheme'] = service.backend.scheme
21
+ env['HTTPS'] = service.backend.scheme.downcase == 'https' ? 'on' : 'off'
22
+
23
+ # This is the only path that needs to be set currently on Rails 5 & greater
24
+ env['PATH_INFO'] = service.backend_path_for(request.path)
25
+
26
+ # don't send your sites cookies to target service, unless it is a trusted internal service that can parse all your cookies
27
+ env['HTTP_COOKIE'] = '' unless service.send_cookies?
28
+
29
+ # other Rack::Proxy opts
30
+ env['rack.ssl_verify_none'] = true unless service.verify_ssl?
31
+ env['http.read_timeout'] = service.read_timeout unless service.read_timeout.nil?
32
+
33
+ env['content-length'] = nil
34
+
35
+ super(env)
36
+ else
37
+ @app.call(env)
38
+ end
39
+ end
40
+
41
+ def rewrite_response(triplet)
42
+ status, headers, body = triplet
43
+ headers['content-length'] = nil
44
+ triplet
45
+ end
46
+
47
+ private
48
+
49
+ def config
50
+ return @config if instance_variable_defined?(:'@config')
51
+
52
+ if File.exist?(Rails.root.join('config/service_proxy.yml'))
53
+ config_data = Rails.application.config_for(:service_proxy)
54
+ @config = Config.new(config_data.deep_symbolize_keys) if config_data
55
+ end
56
+ @config ||= nil
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,9 @@
1
+ module Service
2
+ module Proxy
3
+ class Railtie < ::Rails::Railtie
4
+ initializer 'service.proxy' do |app|
5
+ app.middleware.use Service::Proxy::Middleware
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,39 @@
1
+ module Service
2
+ module Proxy
3
+ class ServiceConfig
4
+ def initialize(name, options)
5
+ @name = name
6
+ @options = options
7
+ end
8
+
9
+ def backend
10
+ @backend ||= URI(@options.fetch(:backend, ''))
11
+ end
12
+
13
+ def backend_path_for(original_path)
14
+ original_path.delete_prefix!(path)
15
+ [backend.path, original_path].compact.join('/').gsub(/\/+/, '/')
16
+ end
17
+
18
+ def path
19
+ @path ||= @options.fetch(:path)
20
+ end
21
+
22
+ def path_regexp
23
+ @path_regexp ||= Regexp.new("^#{Regexp.escape(path)}")
24
+ end
25
+
26
+ def send_cookies?
27
+ @options.fetch(:forward_cookies, true)
28
+ end
29
+
30
+ def verify_ssl?
31
+ @options.fetch(:verify_ssl, true)
32
+ end
33
+
34
+ def read_timeout
35
+ @options.fetch(:read_timeout, nil)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,5 @@
1
+ module Service
2
+ module Proxy
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :service_proxy do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: service-proxy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.12
5
+ platform: ruby
6
+ authors:
7
+ - Sephora Asia
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-06-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 5.2.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: rack-proxy
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.6.5
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.6.5
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sqlite3
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Easily proxy paths in your rails application to other backend services.
70
+ email:
71
+ - dpiret@sephora.sg
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - MIT-LICENSE
77
+ - README.md
78
+ - Rakefile
79
+ - lib/service/proxy.rb
80
+ - lib/service/proxy/config.rb
81
+ - lib/service/proxy/middleware.rb
82
+ - lib/service/proxy/railtie.rb
83
+ - lib/service/proxy/service_config.rb
84
+ - lib/service/proxy/version.rb
85
+ - lib/tasks/service/proxy_tasks.rake
86
+ homepage: https://github.com/sephora-asia/service-proxy-rails
87
+ licenses:
88
+ - MIT
89
+ metadata:
90
+ homepage_uri: https://github.com/sephora-asia/service-proxy-rails
91
+ source_code_uri: https://github.com/sephora-asia/service-proxy-rails
92
+ github_repo: ssh://github.com/sephora-asia/service-proxy-rails
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubygems_version: 3.1.2
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: Easily proxy paths in your rails application to other backend services.
112
+ test_files: []