agile-proxy-jruby 0.1.25-jruby
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.
- 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
|