agile-proxy-jruby 0.1.25-jruby
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.bowerrc +3 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +36 -0
- data/.travis.yml +10 -0
- data/Gemfile +4 -0
- data/Guardfile +20 -0
- data/LICENSE +22 -0
- data/README.md +131 -0
- data/Rakefile +15 -0
- data/agile-proxy.gemspec +60 -0
- data/assets/index.html +39 -0
- data/assets/ui/app/AgileProxyApi.js +31 -0
- data/assets/ui/app/app.js +1 -0
- data/assets/ui/app/controller/Stubs.js +64 -0
- data/assets/ui/app/controller/main.js +12 -0
- data/assets/ui/app/directive/AppEnhancedFormElement.js +21 -0
- data/assets/ui/app/directive/AppFor.js +16 -0
- data/assets/ui/app/directive/AppResponseEditor.js +54 -0
- data/assets/ui/app/model/RequestSpec.js +6 -0
- data/assets/ui/app/routes.js +11 -0
- data/assets/ui/app/service/Dialog.js +49 -0
- data/assets/ui/app/service/DomId.js +10 -0
- data/assets/ui/app/service/Error.js +7 -0
- data/assets/ui/app/service/Stub.js +36 -0
- data/assets/ui/app/view/404.html +2 -0
- data/assets/ui/app/view/dialog/error.html +10 -0
- data/assets/ui/app/view/dialog/yesNo.html +8 -0
- data/assets/ui/app/view/responses/editForm.html +78 -0
- data/assets/ui/app/view/status.html +1 -0
- data/assets/ui/app/view/stubs.html +19 -0
- data/assets/ui/app/view/stubs/edit.html +58 -0
- data/assets/ui/css/main.css +3 -0
- data/bin/agile_proxy +4 -0
- data/bower.json +27 -0
- data/config.yml +6 -0
- data/db.yml +10 -0
- data/db/migrations/20140818110800_create_users.rb +9 -0
- data/db/migrations/20140818134700_create_applications.rb +10 -0
- data/db/migrations/20140818135200_create_request_specs.rb +13 -0
- data/db/migrations/20140821115300_create_responses.rb +14 -0
- data/db/migrations/20140823082900_add_method_to_request_specs.rb +7 -0
- data/db/migrations/20140823083900_rename_request_spec_columns.rb +8 -0
- data/db/migrations/20141031072100_add_url_type_to_request_specs.rb +8 -0
- data/db/migrations/20141105125600_add_conditions_to_request_specs.rb +7 -0
- data/db/migrations/20141106083100_add_username_and_password_to_applications.rb +8 -0
- data/db/migrations/20141119143800_add_record_to_applications.rb +7 -0
- data/db/migrations/20141119174300_create_recordings.rb +18 -0
- data/db/migrations/20150221152500_add_record_requests_to_request_specs.rb +7 -0
- data/db/schema.rb +78 -0
- data/db/seed.rb +26 -0
- data/echo_server.rb +19 -0
- data/examples/README.md +1 -0
- data/examples/facebook_api.html +59 -0
- data/examples/tumblr_api.html +22 -0
- data/lib/agile_proxy.rb +8 -0
- data/lib/agile_proxy/api/applications.rb +77 -0
- data/lib/agile_proxy/api/recordings.rb +52 -0
- data/lib/agile_proxy/api/request_spec_recordings.rb +52 -0
- data/lib/agile_proxy/api/request_specs.rb +86 -0
- data/lib/agile_proxy/api/root.rb +45 -0
- data/lib/agile_proxy/cli.rb +116 -0
- data/lib/agile_proxy/config.rb +66 -0
- data/lib/agile_proxy/handlers/handler.rb +43 -0
- data/lib/agile_proxy/handlers/proxy_handler.rb +111 -0
- data/lib/agile_proxy/handlers/request_handler.rb +75 -0
- data/lib/agile_proxy/handlers/stub_handler.rb +146 -0
- data/lib/agile_proxy/mitm.crt +22 -0
- data/lib/agile_proxy/mitm.key +27 -0
- data/lib/agile_proxy/model/application.rb +20 -0
- data/lib/agile_proxy/model/recording.rb +17 -0
- data/lib/agile_proxy/model/request_spec.rb +48 -0
- data/lib/agile_proxy/model/response.rb +51 -0
- data/lib/agile_proxy/model/user.rb +17 -0
- data/lib/agile_proxy/proxy_connection.rb +112 -0
- data/lib/agile_proxy/rack/get_only_cache.rb +30 -0
- data/lib/agile_proxy/route.rb +106 -0
- data/lib/agile_proxy/router.rb +99 -0
- data/lib/agile_proxy/server.rb +119 -0
- data/lib/agile_proxy/servers/api.rb +40 -0
- data/lib/agile_proxy/servers/request_spec.rb +40 -0
- data/lib/agile_proxy/servers/request_spec_direct.rb +35 -0
- data/lib/agile_proxy/version.rb +6 -0
- data/load_proxy.js +39 -0
- data/log/.gitkeep +0 -0
- data/spec/common_helper.rb +32 -0
- data/spec/fixtures/example_static_file.html +1 -0
- data/spec/fixtures/test-server.crt +15 -0
- data/spec/fixtures/test-server.key +15 -0
- data/spec/integration/helpers/request_spec_helper.rb +84 -0
- data/spec/integration/specs/lib/server_spec.rb +474 -0
- data/spec/integration_spec_helper.rb +16 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/test_server.rb +105 -0
- data/spec/unit/agile_proxy/api/applications_spec.rb +102 -0
- data/spec/unit/agile_proxy/api/common_helper.rb +31 -0
- data/spec/unit/agile_proxy/api/recordings_spec.rb +115 -0
- data/spec/unit/agile_proxy/api/request_spec_recordings_spec.rb +119 -0
- data/spec/unit/agile_proxy/api/request_specs_spec.rb +159 -0
- data/spec/unit/agile_proxy/handlers/handler_spec.rb +8 -0
- data/spec/unit/agile_proxy/handlers/proxy_handler_spec.rb +138 -0
- data/spec/unit/agile_proxy/handlers/request_handler_spec.rb +76 -0
- data/spec/unit/agile_proxy/handlers/stub_handler_spec.rb +177 -0
- data/spec/unit/agile_proxy/model/recording_spec.rb +0 -0
- data/spec/unit/agile_proxy/model/request_spec_spec.rb +45 -0
- data/spec/unit/agile_proxy/model/response_spec.rb +38 -0
- data/spec/unit/agile_proxy/server_spec.rb +91 -0
- data/spec/unit/agile_proxy/servers/api_spec.rb +35 -0
- data/spec/unit/agile_proxy/servers/request_spec_direct_spec.rb +51 -0
- data/spec/unit/agile_proxy/servers/request_spec_spec.rb +35 -0
- metadata +736 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
module AgileProxy
|
2
|
+
module Api
|
3
|
+
#
|
4
|
+
# = A grape API for recordings
|
5
|
+
#
|
6
|
+
# If the application is set to allow recordings, each HTTP request and response passing
|
7
|
+
# through the proxy server will be recorded.
|
8
|
+
#
|
9
|
+
# This API allows access to those recordings via REST
|
10
|
+
#
|
11
|
+
class Recordings < Grape::API
|
12
|
+
include Grape::Kaminari
|
13
|
+
helpers do
|
14
|
+
# Convenient access to the record specified in the id parameter
|
15
|
+
def record
|
16
|
+
current_application.recordings.where(id: params[:id]).first
|
17
|
+
end
|
18
|
+
|
19
|
+
def default_json_spec
|
20
|
+
{}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
resource :recordings do
|
25
|
+
desc 'List all recordings made for the application'
|
26
|
+
paginate per_page: 20, max_per_page: 200
|
27
|
+
get do
|
28
|
+
authenticate!
|
29
|
+
scope = current_application.recordings
|
30
|
+
{ recordings: paginate(scope).as_json(default_json_spec), total: scope.count }
|
31
|
+
end
|
32
|
+
desc 'Delete all rcordings for the application'
|
33
|
+
delete do
|
34
|
+
authenticate!
|
35
|
+
scope = current_application.recordings
|
36
|
+
scope.destroy_all
|
37
|
+
{ recordings: [], total: 0 }
|
38
|
+
end
|
39
|
+
desc 'Get a recording by id'
|
40
|
+
get ':id' do
|
41
|
+
authenticate!
|
42
|
+
record.as_json(default_json_spec)
|
43
|
+
end
|
44
|
+
delete ':id' do
|
45
|
+
authenticate!
|
46
|
+
record.tap(&:destroy).as_json(default_json_spec)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module AgileProxy
|
2
|
+
module Api
|
3
|
+
#
|
4
|
+
# = A grape API for recordings
|
5
|
+
#
|
6
|
+
# If the application is set to allow recordings, each HTTP request and response passing
|
7
|
+
# through the proxy server will be recorded.
|
8
|
+
#
|
9
|
+
# This API allows access to those recordings via REST
|
10
|
+
#
|
11
|
+
class RequestSpecRecordings < Grape::API
|
12
|
+
include Grape::Kaminari
|
13
|
+
helpers do
|
14
|
+
# Convenient access to the record specified in the id parameter
|
15
|
+
def record
|
16
|
+
current_application.recordings.where(request_spec_id: params[:request_spec_id], id: params[:id]).first
|
17
|
+
end
|
18
|
+
|
19
|
+
def default_json_spec
|
20
|
+
{}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
resource :recordings do
|
25
|
+
desc 'List all recordings made for the request spec'
|
26
|
+
paginate per_page: 20, max_per_page: 200
|
27
|
+
get do
|
28
|
+
authenticate!
|
29
|
+
scope = current_application.recordings.where({request_spec_id: params[:request_spec_id]})
|
30
|
+
{ recordings: paginate(scope).as_json(default_json_spec), total: scope.count }
|
31
|
+
end
|
32
|
+
desc 'Delete all recordings for the application'
|
33
|
+
delete do
|
34
|
+
authenticate!
|
35
|
+
scope = current_application.recordings
|
36
|
+
scope.destroy_all request_spec_id: params[:request_spec_id]
|
37
|
+
{ recordings: [], total: 0 }
|
38
|
+
end
|
39
|
+
desc 'Get a recording by id'
|
40
|
+
get ':id' do
|
41
|
+
authenticate!
|
42
|
+
record.as_json(default_json_spec)
|
43
|
+
end
|
44
|
+
delete ':id' do
|
45
|
+
authenticate!
|
46
|
+
record.tap(&:destroy).as_json(default_json_spec)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'agile_proxy/model/request_spec'
|
2
|
+
require 'grape-kaminari'
|
3
|
+
module AgileProxy
|
4
|
+
module Api
|
5
|
+
#
|
6
|
+
# = A grape API for request specifications
|
7
|
+
#
|
8
|
+
# A 'request specification' is what is known as a 'Stub' in the UI.
|
9
|
+
#
|
10
|
+
# It defines an input and output spec for a HTTP(s) request.
|
11
|
+
#
|
12
|
+
# For example, we could say
|
13
|
+
# 'When http://www.mybing.com/search.html is requested with some specific query parameters, then respond with this'
|
14
|
+
#
|
15
|
+
# This API allows full CRUD access to these request specifications, but only those belonging to the logged in user.
|
16
|
+
#
|
17
|
+
class RequestSpecs < Grape::API
|
18
|
+
include Grape::Kaminari
|
19
|
+
helpers do
|
20
|
+
# We only allow selected parameters through - spec and note
|
21
|
+
def permitted_params
|
22
|
+
@permitted_params ||= declared(
|
23
|
+
params,
|
24
|
+
{ include_missing: false },
|
25
|
+
[:spec, :note, :response, :http_method, :url, :url_type, :conditions, :record_requests]
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Convenient access to the record specified in the id parameter
|
30
|
+
def record
|
31
|
+
current_application.request_specs.where(id: params[:id]).first
|
32
|
+
end
|
33
|
+
|
34
|
+
# Convenient access to the record parameters from a POST or a PUT, only permitted will be returned
|
35
|
+
# Note that for some reason, to do with rack or grape,
|
36
|
+
# when we send a large body, the request_spec does not come through
|
37
|
+
# so, to work around this, we inject the request spec in afterwards if it is missing.
|
38
|
+
def record_params
|
39
|
+
p = permitted_params.with_indifferent_access
|
40
|
+
p.merge!(user_id: current_user.id, application_id: current_application.id)
|
41
|
+
p[:response_attributes] = p.delete(:response) if p.key?(:response)
|
42
|
+
p
|
43
|
+
end
|
44
|
+
|
45
|
+
def default_json_spec
|
46
|
+
{ include: { response: { except: [:created_at, :updated_at] } } }
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
resource :request_specs do
|
51
|
+
desc 'List all request specifications for the application'
|
52
|
+
paginate per_page: 50, max_per_page: 200
|
53
|
+
get do
|
54
|
+
authenticate!
|
55
|
+
scope = current_application.request_specs
|
56
|
+
{ request_specs: paginate(scope).as_json(default_json_spec), total: scope.count }
|
57
|
+
end
|
58
|
+
delete do
|
59
|
+
authenticate!
|
60
|
+
scope = current_application.request_specs
|
61
|
+
scope.destroy_all
|
62
|
+
{ request_specs: [], total: 0 }
|
63
|
+
end
|
64
|
+
desc 'Create a new request specification'
|
65
|
+
post do
|
66
|
+
authenticate!
|
67
|
+
current_application.request_specs.create(record_params).as_json(default_json_spec)
|
68
|
+
end
|
69
|
+
get ':id' do
|
70
|
+
authenticate!
|
71
|
+
record.as_json(default_json_spec)
|
72
|
+
end
|
73
|
+
desc 'Update a request specification'
|
74
|
+
put ':id' do
|
75
|
+
authenticate!
|
76
|
+
record.tap { |r| r.update_attributes(record_params) }.as_json(default_json_spec)
|
77
|
+
end
|
78
|
+
delete ':id' do
|
79
|
+
authenticate!
|
80
|
+
record.tap(&:destroy).as_json(default_json_spec)
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative 'request_specs'
|
2
|
+
require_relative 'request_spec_recordings'
|
3
|
+
require_relative 'applications'
|
4
|
+
require_relative 'recordings'
|
5
|
+
module AgileProxy
|
6
|
+
module Api
|
7
|
+
#
|
8
|
+
# = The API Root
|
9
|
+
#
|
10
|
+
# This is the root of the entire API for use with REST. It will not be accessed directly
|
11
|
+
#
|
12
|
+
class Root < Grape::API
|
13
|
+
version 'v1', vendor: 'agile-proxy'
|
14
|
+
format :json
|
15
|
+
helpers do
|
16
|
+
# Provides easy access to the current user.
|
17
|
+
# As we are currently only single user, then we just return the first user
|
18
|
+
def current_user
|
19
|
+
::AgileProxy::User.first
|
20
|
+
end
|
21
|
+
# Secured methods must call this first
|
22
|
+
def authenticate!
|
23
|
+
# Do nothing yet
|
24
|
+
end
|
25
|
+
# Provides easy access to the current application whether
|
26
|
+
# specified in the URL or not (defaults to the first if not)
|
27
|
+
def current_application
|
28
|
+
fail 'Application ID is missing' unless params.key?(:application_id)
|
29
|
+
applications = current_user.applications
|
30
|
+
applications.where(id: params[:application_id]).first
|
31
|
+
end
|
32
|
+
end
|
33
|
+
namespace 'users/:user_id' do
|
34
|
+
mount Api::Applications
|
35
|
+
namespace '/applications/:application_id' do
|
36
|
+
mount Api::Recordings
|
37
|
+
mount Api::RequestSpecs
|
38
|
+
namespace '/request_specs/:request_spec_id' do
|
39
|
+
mount Api::RequestSpecRecordings
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'agile_proxy'
|
2
|
+
require 'thor'
|
3
|
+
require 'active_record'
|
4
|
+
require_relative '../../db/seed'
|
5
|
+
|
6
|
+
module AgileProxy
|
7
|
+
include ActiveRecord::Tasks
|
8
|
+
class Cli < Thor
|
9
|
+
class << self
|
10
|
+
def data_dir_base
|
11
|
+
if RUBY_PLATFORM =~ /win32/
|
12
|
+
ENV['APPDATA']
|
13
|
+
elsif RUBY_PLATFORM =~ /linux/
|
14
|
+
ENV['HOME']
|
15
|
+
elsif RUBY_PLATFORM =~ /darwin/
|
16
|
+
ENV['HOME']
|
17
|
+
elsif RUBY_PLATFORM =~ /freebsd/
|
18
|
+
ENV['HOME']
|
19
|
+
else
|
20
|
+
ENV['HOME']
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def data_dir
|
25
|
+
if Dir.pwd == File.expand_path('../..', File.dirname(__FILE__))
|
26
|
+
Dir.pwd
|
27
|
+
else
|
28
|
+
File.join data_dir_base, '.agile_proxy'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def environment
|
33
|
+
ENV['AGILE_PROXY_ENV'] || (Dir.pwd == File.expand_path('../..', File.dirname(__FILE__)) ? 'development' : 'production')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
package_name 'Http Flexible Proxy'
|
37
|
+
desc 'start PROXY_PORT WEBSERVER_PORT', 'Runs the agile proxy'
|
38
|
+
method_options data_dir: data_dir, database_config_file: 'db.yml', env: environment
|
39
|
+
def start(proxy_port = nil, server_port = nil, webserver_port = nil)
|
40
|
+
ensure_database_config_file_exists database_config_file(options)
|
41
|
+
puts "Data dir is #{options.data_dir}, environment is #{options.env}"
|
42
|
+
setup_for_migrations(options)
|
43
|
+
::AgileProxy.configure do |config|
|
44
|
+
config.proxy_port = proxy_port unless proxy_port.nil?
|
45
|
+
config.server_port = server_port unless server_port.nil?
|
46
|
+
config.webserver_port = webserver_port unless webserver_port.nil?
|
47
|
+
config.environment = options.env
|
48
|
+
config.database_config_file = database_config_file(options)
|
49
|
+
end
|
50
|
+
server = AgileProxy::Server.new
|
51
|
+
update_db
|
52
|
+
server.start
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def setup_for_migrations(options)
|
58
|
+
ActiveRecord::Tasks::DatabaseTasks.db_dir = options.data_dir
|
59
|
+
ActiveRecord::Tasks::DatabaseTasks.migrations_paths = [File.expand_path('../../db/migrations', File.dirname(__FILE__))]
|
60
|
+
ActiveRecord::Tasks::DatabaseTasks.env = options.env
|
61
|
+
ActiveRecord::Tasks::DatabaseTasks.root = File.expand_path('../..', __FILE__)
|
62
|
+
ActiveRecord::Migrator.migrations_paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths
|
63
|
+
end
|
64
|
+
def run_migrations
|
65
|
+
ActiveRecord::Migration.verbose = true
|
66
|
+
ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, nil) do |migration|
|
67
|
+
ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def seed_database
|
72
|
+
Seed.load_seed
|
73
|
+
end
|
74
|
+
|
75
|
+
def server
|
76
|
+
AgileProxy::Server.new
|
77
|
+
end
|
78
|
+
|
79
|
+
def update_db
|
80
|
+
ActiveRecord::Tasks::DatabaseTasks.create_current
|
81
|
+
run_migrations
|
82
|
+
seed_database
|
83
|
+
# Rake::Task['db:create'].invoke
|
84
|
+
# Rake::Task['db:migrate'].invoke
|
85
|
+
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
def ensure_database_config_file_exists(fn)
|
90
|
+
return if File.exist? fn
|
91
|
+
FileUtils.mkdir_p File.dirname fn
|
92
|
+
db = {
|
93
|
+
:development => {
|
94
|
+
adapter: 'sqlite3',
|
95
|
+
database: File.join(File.dirname(fn), 'db', 'development.db')
|
96
|
+
},
|
97
|
+
:test => {
|
98
|
+
adapter: 'sqlite3',
|
99
|
+
database: File.join(File.dirname(fn), 'db', 'test.db')
|
100
|
+
},
|
101
|
+
:production => {
|
102
|
+
adapter: 'sqlite3',
|
103
|
+
database: File.join(File.dirname(fn), 'db', 'production.db')
|
104
|
+
}
|
105
|
+
}
|
106
|
+
File.open(fn, 'w') {|f| f.write(db.to_yaml) }
|
107
|
+
end
|
108
|
+
def database_config_file(options)
|
109
|
+
if File.exist? options.database_config_file
|
110
|
+
options.database_config_file
|
111
|
+
else
|
112
|
+
File.join(options.data_dir, options.database_config_file)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'tmpdir'
|
3
|
+
# Agile Proxy
|
4
|
+
module AgileProxy
|
5
|
+
#
|
6
|
+
# Configuration for the agile proxy
|
7
|
+
class Config
|
8
|
+
DEFAULT_WHITELIST = ['127.0.0.1', 'localhost']
|
9
|
+
RANDOM_AVAILABLE_PORT = 0 # https://github.com/eventmachine/eventmachine/wiki/FAQ#wiki-can-i-start-a-server-on-a-random-available-port
|
10
|
+
|
11
|
+
attr_accessor :logger, :cache, :cache_request_headers, :whitelist, :path_blacklist, :ignore_params,
|
12
|
+
:persist_cache, :ignore_cache_port, :non_successful_cache_disabled, :non_successful_error_level,
|
13
|
+
:non_whitelisted_requests_disabled, :cache_path, :proxy_port, :proxied_request_inactivity_timeout,
|
14
|
+
:proxied_request_connect_timeout, :dynamic_jsonp, :dynamic_jsonp_keys,
|
15
|
+
:webserver_host, :webserver_port, :server_host, :server_port, :database_config_file, :environment, :enable_cache
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@logger = defined?(Rails) ? Rails.logger : Logger.new(STDOUT)
|
19
|
+
reset
|
20
|
+
end
|
21
|
+
|
22
|
+
# Resets the configuration with the defaults
|
23
|
+
def reset
|
24
|
+
@cache = true
|
25
|
+
@cache_request_headers = false
|
26
|
+
@whitelist = DEFAULT_WHITELIST
|
27
|
+
@path_blacklist = []
|
28
|
+
@ignore_params = []
|
29
|
+
@persist_cache = false
|
30
|
+
@dynamic_jsonp = false
|
31
|
+
@dynamic_jsonp_keys = ['callback']
|
32
|
+
@ignore_cache_port = true
|
33
|
+
@non_successful_cache_disabled = false
|
34
|
+
@non_successful_error_level = :warn
|
35
|
+
@non_whitelisted_requests_disabled = false
|
36
|
+
@cache_path = File.join(Dir.tmpdir, 'agile-proxy')
|
37
|
+
@proxy_port = RANDOM_AVAILABLE_PORT
|
38
|
+
@proxied_request_inactivity_timeout = 10 # defaults from https://github.com/igrigorik/em-http-request/wiki/Redirects-and-Timeouts
|
39
|
+
@proxied_request_connect_timeout = 5
|
40
|
+
@webserver_port = 3020
|
41
|
+
@webserver_host = 'localhost'
|
42
|
+
@server_port = 3030
|
43
|
+
@server_host = 'localhost'
|
44
|
+
@database_config_file = File.join(File.dirname(__FILE__), '..', '..', 'config.yml')
|
45
|
+
@environment = ENV['AGILE_PROXY_ENV']
|
46
|
+
@enable_cache = false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Configures the system using a block which has the global instance of this config yielded
|
51
|
+
def self.configure
|
52
|
+
yield config if block_given?
|
53
|
+
config
|
54
|
+
end
|
55
|
+
|
56
|
+
# Common log method - sends the log to the appropriate place
|
57
|
+
def self.log(*args)
|
58
|
+
config.logger.send(*args) unless config.logger.nil?
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def self.config
|
64
|
+
@config ||= Config.new
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rack'
|
2
|
+
module AgileProxy
|
3
|
+
# A mixin that all handlers must include
|
4
|
+
module Handler
|
5
|
+
##
|
6
|
+
#
|
7
|
+
# Handles an incoming rack request and returns a rack response.
|
8
|
+
#
|
9
|
+
# This method accepts rack request parameters and must return
|
10
|
+
# a rack response array containing [status, headers, content]
|
11
|
+
# , or [404, {}, ''] if the request cannot be fulfilled.
|
12
|
+
#
|
13
|
+
# @param _env [Hash] The rack environment
|
14
|
+
# @return [Array] An array of [status, headers, content]
|
15
|
+
# Returns status of 404 if the request cannot be fulfilled.
|
16
|
+
def call(_env)
|
17
|
+
[500, {}, 'The handler has not overridden the handle_request method!']
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def username_password(env)
|
23
|
+
Base64.decode64(env['HTTP_PROXY_AUTHORIZATION'].sub(/^Basic /, '')).split(':') if proxy_auth? env
|
24
|
+
end
|
25
|
+
|
26
|
+
def proxy_auth?(env)
|
27
|
+
env.key?('HTTP_PROXY_AUTHORIZATION') && env['HTTP_PROXY_AUTHORIZATION'] =~ /^Basic /
|
28
|
+
end
|
29
|
+
|
30
|
+
def downcase_header_name(name)
|
31
|
+
name.split(/_/).drop(1).map { |word| word.downcase.capitalize }.join('-')
|
32
|
+
end
|
33
|
+
|
34
|
+
def downcased_headers(env)
|
35
|
+
headers = {}
|
36
|
+
env.each do |name, value|
|
37
|
+
next unless name =~ /^HTTP_/
|
38
|
+
headers[downcase_header_name(name)] = value
|
39
|
+
end
|
40
|
+
headers
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|