agile-proxy 0.1.20 → 0.1.21

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7faec1aa540783f6fe42b674e1aeea119a470b15
4
- data.tar.gz: 1b01c98d23e6c95eb894601b4b05c3420a4219df
3
+ metadata.gz: dca50b88e4dff710583bb65d8dfeea362efe0194
4
+ data.tar.gz: ce452e942ba2a2b186b74d95e34048abb001098c
5
5
  SHA512:
6
- metadata.gz: 43f930138c348608ef2972536c2192c08716b4603a2bb9234108926da5d2d8e532a9618082a7a54b7f1212e5711d35eb79e0fcd455a31aa33dac3895ced35789
7
- data.tar.gz: bfbdf55b64323489c085822e565f1a32f2f3447684142f36c9bf48de9e2a7a9ffc7379bf7b400450e5dafbfe4ce1b799225c4c0bb4754d92950ee3ceb56a574e
6
+ metadata.gz: 42012c6b32b17916cdd7b5b592f434e7db5eb50dd6fd2b9c8f2cf6715631d295f490e4dc73fb72e6b6ba59c238572833c9d9da8167dbe0451ddecbef2ae4d04e
7
+ data.tar.gz: 3ed48c70d0599bb27c7956ccec8e7fa2c14e89feb9644f2375cf5703c793544c30c1a62252055b66fddf94888ef1827f5ea4500dad8148791f527ca9136000e2
data/.gitignore CHANGED
@@ -6,4 +6,5 @@ assets/ui/bower_components
6
6
  .yardoc
7
7
  db/*.db
8
8
  coverage/
9
- Gemfile.lock
9
+ Gemfile.lock
10
+ vendor/gems
data/README.md CHANGED
@@ -122,4 +122,5 @@ v0.1.18 - Fixed issue with integration test which was showing up now that travis
122
122
  v0.1.19 - Recordings now record the request spec id.
123
123
  Recordings can now be accessed via /request_specs/:request_spec_id/recordings to provide recordings specific to the request spec
124
124
  v0.1.20 - An individual request spec can now be set to 'record_requests' rather than requiring the whole application to be in record mode which slows down every request
125
+ v0.1.21 - Switched to goliath instead of thin. The gem now installs under jruby as well as other platforms.
125
126
 
@@ -21,11 +21,9 @@ Gem::Specification.new do |gem|
21
21
  gem.add_development_dependency 'faraday', '~> 0.9', '>= 0.9.0'
22
22
  gem.add_development_dependency 'poltergeist', '~> 1.5', '>= 1.5.1'
23
23
  gem.add_development_dependency 'selenium-webdriver', '~> 2.43', '>= 2.43.0'
24
- gem.add_development_dependency 'rack', '~> 1.6', '>= 1.6.0'
25
24
  gem.add_development_dependency 'guard', '~> 2.6', '>= 2.6.1'
26
25
  gem.add_development_dependency 'rb-inotify', '~> 0.9', '>= 0.9.5'
27
26
  gem.add_development_dependency 'cucumber', '~> 1.3', '>= 1.3.17'
28
- gem.add_development_dependency 'airborne', '~> 0.1', '>= 0.1.10'
29
27
  gem.add_development_dependency 'rest-client', '~> 1.7', '>= 1.7.2'
30
28
  gem.add_development_dependency 'require_all', '~> 1.3', '>= 1.3.2'
31
29
  gem.add_development_dependency 'faker', '~> 1.2', '>= 1.2.0'
@@ -35,16 +33,24 @@ Gem::Specification.new do |gem|
35
33
  gem.add_runtime_dependency 'eventmachine', '~> 1.0', '>= 1.0.3'
36
34
  gem.add_runtime_dependency 'em-synchrony', '~> 1.0', '>= 1.0.3'
37
35
  gem.add_runtime_dependency 'em-http-request', '~> 1.1', '>= 1.1.2'
38
- gem.add_runtime_dependency 'eventmachine_httpserver', '~> 0.2', '>= 0.2.1'
39
- gem.add_runtime_dependency 'http_parser.rb', '~> 0.6', '>= 0.6.0'
40
- gem.add_runtime_dependency 'multi_json', '~> 1.10', '>= 1.10.1'
41
- gem.add_runtime_dependency 'thin', '~> 1.6', '>= 1.6.2'
42
36
  gem.add_runtime_dependency 'grape', '~> 0.10', '>= 0.10.1'
43
37
  gem.add_runtime_dependency 'activerecord', '~> 4.2', '>= 4.2.0'
44
- gem.add_runtime_dependency 'sqlite3', '~> 1.3', '>= 1.3.10'
38
+ if RUBY_PLATFORM =~ /java/
39
+ #JVM Only
40
+ gem.add_runtime_dependency 'activerecord-jdbc-adapter'
41
+ gem.add_runtime_dependency 'activerecord-jdbcsqlite3-adapter'
42
+ else
43
+ #Non JVM
44
+ gem.add_runtime_dependency 'sqlite3', '~> 1.3', '>= 1.3.10'
45
+ end
46
+
47
+
48
+
45
49
  gem.add_runtime_dependency 'grape-kaminari', '~> 0.1', '>= 0.1.7'
46
50
  gem.add_runtime_dependency 'shoulda-matchers', '2.8.0.rc2'
47
51
  gem.add_runtime_dependency 'flavour_saver', '~> 0.3', '>= 0.3.4'
48
52
  gem.add_runtime_dependency 'thor', '~> 0.19', '>= 0.19.1'
49
- gem.add_runtime_dependency 'rack-parser', '~> 0.6', '>= 0.6.1'
53
+ gem.add_runtime_dependency 'goliath', '~> 1.0', '>= 1.0.4'
54
+ gem.add_runtime_dependency 'goliath-proxy', '~> 0.0', '>= 0.0.1'
55
+
50
56
  end
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'goliath'
4
+ require 'active_support/core_ext/class/attribute_accessors'
5
+ class Echo < Goliath::API
6
+ cattr_accessor :counter
7
+ def response_code
8
+ ENV['STATUS_CODE'] || 200
9
+ end
10
+ def response(env)
11
+ self.counter = counter || 0
12
+ req_body = env['rack.input'].read
13
+ request_info = "#{env['REQUEST_METHOD']} #{env['PATH_INFO']}"
14
+ res_body = request_info
15
+ res_body += "\n#{req_body}" unless req_body.empty?
16
+ self.counter += 1
17
+ [response_code, { 'HTTP-X-EchoServer' => request_info, 'HTTP-X-EchoCount' => "#{counter}" }, res_body]
18
+ end
19
+ end
@@ -36,8 +36,9 @@ module AgileProxy
36
36
  ]
37
37
  end
38
38
  request_spec = env['agile_proxy.request_spec']
39
+ exclude_headers = ['@env', 'rack.errors', 'rack.logger']
39
40
  if application.record_requests || (request_spec && request_spec.record_requests)
40
- application.recordings.create request_headers: request.headers,
41
+ application.recordings.create request_headers: request.headers.reject {|key, value| exclude_headers.include?(key)},
41
42
  request_body: body,
42
43
  request_url: request.url,
43
44
  request_method: request.request_method,
@@ -2,7 +2,6 @@ require 'agile_proxy/handlers/handler'
2
2
  require 'agile_proxy/model/request_spec'
3
3
  require 'agile_proxy/router'
4
4
  require 'agile_proxy/model/application'
5
- require 'rack/parser'
6
5
  require 'action_dispatch'
7
6
  require 'base64'
8
7
  module AgileProxy
@@ -1,4 +1,5 @@
1
1
  require_relative 'application'
2
+ require 'active_record'
2
3
  module AgileProxy
3
4
  #
4
5
  # = The recording model
@@ -1,24 +1,27 @@
1
1
  require 'uri'
2
2
  require 'eventmachine'
3
- require 'http/parser'
4
- require 'em-http'
5
- require 'evma_httpserver'
6
- require 'em-synchrony'
7
3
  require 'stringio'
8
4
  require 'rack'
5
+ require 'goliath/request'
6
+ require 'goliath/env'
9
7
 
10
8
  module AgileProxy
11
9
  #
12
10
  # = The Proxy Connection
13
11
  #
14
12
  # This class is the event machine connection used by the proxy. Every request creates a new instance of this
15
- class ProxyConnection < EventMachine::Connection
16
- attr_accessor :handler
13
+ class ProxyConnection < Goliath::Connection
14
+ def logger
15
+ ::AgileProxy.config.logger
16
+ end
17
17
  def post_init
18
- @parser = Http::Parser.new(self)
18
+ super
19
+ #@proxy_parser = Http::Parser.new(self)
20
+ @proxy_parser = Http::Parser.new
19
21
  end
20
22
 
21
23
  def receive_data(data)
24
+ #@proxy_parser << data
22
25
  @parser << data
23
26
  end
24
27
 
@@ -36,24 +39,25 @@ module AgileProxy
36
39
  end
37
40
 
38
41
  def on_message_complete
39
- if @parser.http_method == 'CONNECT'
40
- restart_with_ssl(@parser.request_url)
42
+ if @proxy_parser.http_method == 'CONNECT'
43
+ restart_with_ssl(@proxy_parser.request_url)
41
44
  else
42
45
  if @ssl
43
- uri = URI.parse(@parser.request_url)
46
+ uri = URI.parse(@proxy_parser.request_url)
44
47
  @url = "https://#{@ssl}#{[uri.path, uri.query].compact.join('?')}"
45
48
  else
46
- @url = @parser.request_url
49
+ @url = @proxy_parser.request_url
47
50
  end
48
51
  handle_request
49
52
  end
50
53
  end
51
54
 
55
+
52
56
  protected
53
57
 
54
58
  def restart_with_ssl(url)
55
59
  @ssl = url
56
- @parser = Http::Parser.new(self)
60
+ @proxy_parser = Http::Parser.new(self)
57
61
  @original_headers = @headers.clone
58
62
  send_data("HTTP/1.0 200 Connection established\r\nProxy-agent: Http-Flexible-Proxy/0.0.0\r\n\r\n")
59
63
  start_tls(
@@ -64,11 +68,9 @@ module AgileProxy
64
68
 
65
69
  def handle_request
66
70
  EM.synchrony do
67
- request = ActionDispatch::Request.new(env)
68
- request.params # This will populate action_dispatch.request.parameters
69
- handler.call(env).tap do |response|
70
- send_response(response)
71
- end
71
+ request = ::Goliath::Request.new(handler, self, env)
72
+ request.set_deferred_status :succeeded
73
+ request.process
72
74
  end
73
75
  end
74
76
 
@@ -79,10 +81,11 @@ module AgileProxy
79
81
  fake_input_buffer = StringIO.new(@body)
80
82
  fake_error_buffer = StringIO.new
81
83
  url_parsed = URI.parse(@url)
82
- @__env = {
84
+ @__env = ::Goliath::Env.new
85
+ @__env.merge!({
83
86
  'rack.input' => Rack::Lint::InputWrapper.new(fake_input_buffer),
84
87
  'rack.errors' => Rack::Lint::ErrorWrapper.new(fake_error_buffer),
85
- 'REQUEST_METHOD' => @parser.http_method,
88
+ 'REQUEST_METHOD' => @proxy_parser.http_method,
86
89
  'REQUEST_PATH' => url_parsed.path,
87
90
  'PATH_INFO' => url_parsed.path,
88
91
  'QUERY_STRING' => url_parsed.query || '',
@@ -90,9 +93,11 @@ module AgileProxy
90
93
  'rack.url_scheme' => url_parsed.scheme,
91
94
  'CONTENT_LENGTH' => @body.length,
92
95
  'SERVER_NAME' => url_parsed.host,
93
- 'SERVER_PORT' => url_parsed.port
96
+ 'SERVER_PORT' => url_parsed.port,
97
+ 'rack.logger' => logger
94
98
 
95
- }
99
+
100
+ })
96
101
  @headers.merge(@original_headers || {}).each do |name, value|
97
102
  converted_name = "HTTP_#{name.gsub(/-/, '_').upcase}"
98
103
  @__env[converted_name] = value
@@ -102,12 +107,6 @@ module AgileProxy
102
107
  @__env
103
108
  end
104
109
 
105
- def send_response(response)
106
- res = EM::DelegatedHttpResponse.new(self)
107
- res.status = response[0]
108
- res.headers = response[1]
109
- res.content = response[2]
110
- res.send_response
111
- end
110
+
112
111
  end
113
112
  end
@@ -3,13 +3,27 @@ require 'yaml'
3
3
  require 'cgi'
4
4
  require 'uri'
5
5
  require 'eventmachine'
6
- require 'thin'
7
6
  require 'grape'
8
7
  require 'agile_proxy/api/root'
9
8
  require 'agile_proxy/servers/api'
10
9
  require 'agile_proxy/servers/request_spec'
11
10
  require 'agile_proxy/servers/request_spec_direct'
12
11
  require 'forwardable'
12
+
13
+ require 'goliath/api'
14
+ require 'goliath/runner'
15
+
16
+ # Example demonstrating how to use a custom Goliath runner
17
+ #
18
+
19
+ class Custom < Goliath::API
20
+ def response(env)
21
+ [200, {}, "hello!"]
22
+ end
23
+ end
24
+
25
+
26
+
13
27
  module AgileProxy
14
28
  #
15
29
  # This class is responsible for controlling the underlying proxy and web servers
@@ -1,6 +1,7 @@
1
1
  require 'rack'
2
- require 'thin'
3
2
  require 'grape'
3
+ require 'goliath/api'
4
+ require 'goliath/runner'
4
5
  require 'agile_proxy/api/root'
5
6
 
6
7
  module AgileProxy
@@ -19,21 +20,19 @@ module AgileProxy
19
20
  # @param webserver_host [String] The host for the server to run on
20
21
  # @param webserver_port [Integer] The port for the server to run on
21
22
  def start(webserver_host, webserver_port)
22
- # The sinatra web server
23
- dispatch = Rack::Builder.app do
23
+ #
24
+ # The API runner
25
+ runner = ::Goliath::Runner.new([], nil)
26
+ runner.address = webserver_host
27
+ runner.port = webserver_port
28
+ runner.app = ::Goliath::Rack::Builder.app do
24
29
  use Rack::Static, root: File.join(ROOT, 'assets'), urls: ['/ui'], index: 'index.html'
25
30
  map '/api' do
26
31
  run ::AgileProxy::Api::Root.new
27
32
  end
28
33
  end
29
- # Start the web server.
30
- ::Rack::Server.start(
31
- app: dispatch,
32
- server: 'thin',
33
- Host: webserver_host,
34
- Port: webserver_port,
35
- signals: false
36
- )
34
+ runner.run
35
+
37
36
  end
38
37
  end
39
38
  end
@@ -1,4 +1,6 @@
1
1
  require 'eventmachine'
2
+ require 'goliath/api'
3
+ require 'goliath/proxy'
2
4
  module AgileProxy
3
5
  module Servers
4
6
  #
@@ -6,6 +8,7 @@ module AgileProxy
6
8
  # This server is responsible for handling or passing through a request, depending
7
9
  # on if it has a matching 'Request Specification'
8
10
  class RequestSpec
11
+
9
12
  # Starts the server
10
13
  def self.start
11
14
  new.start
@@ -15,16 +18,23 @@ module AgileProxy
15
18
  end
16
19
  # Starts the server
17
20
  def start
18
- @signature = EM.start_server('127.0.0.1', AgileProxy.config.proxy_port, ProxyConnection) do |p|
19
- p.handler = @request_handler
20
- end
21
+ #
22
+ # The API runner
23
+ runner = ::Goliath::Proxy::Runner.new([], nil)
24
+ runner.address = '127.0.0.1'
25
+ runner.port = AgileProxy.config.proxy_port
26
+ app = @request_handler
27
+ runner.app = app
28
+ runner.run
21
29
  self
30
+
22
31
  end
23
32
  # The port the server is running on
24
33
  # @return [Integer] The port the server is running on
25
34
  def port
26
- Socket.unpack_sockaddr_in(EM.get_sockname(@signature)).first
35
+ return AgileProxy.config.proxy_port
27
36
  end
37
+ private
28
38
  end
29
39
  end
30
40
  end
@@ -1,6 +1,6 @@
1
1
  require 'rack'
2
- require 'thin'
3
-
2
+ require 'goliath/api'
3
+ require 'goliath/runner'
4
4
  module AgileProxy
5
5
  module Servers
6
6
  #
@@ -17,21 +17,17 @@ module AgileProxy
17
17
  # @param server_host [String] The host for the server to run on
18
18
  # @param server_port [Integer] The port for the server to run on
19
19
  def start(server_host, server_port, static_dirs = [])
20
- # The sinatra web server
21
- dispatch = Rack::Builder.app do
20
+
21
+ runner = ::Goliath::Runner.new([], nil)
22
+ runner.address = server_host
23
+ runner.port = server_port
24
+ runner.app = ::Goliath::Rack::Builder.app do
22
25
  use Rack::Static, root: File.join(ROOT, 'assets'), urls: static_dirs, index: 'index.html' unless static_dirs.empty?
23
26
  map '/' do
24
27
  run ::AgileProxy::StubHandler.new
25
28
  end
26
29
  end
27
- # Start the web server.
28
- ::Rack::Server.start(
29
- app: dispatch,
30
- server: 'thin',
31
- Host: server_host,
32
- Port: server_port,
33
- signals: false
34
- )
30
+ runner.run
35
31
  end
36
32
  end
37
33
  end
@@ -2,5 +2,5 @@
2
2
  #
3
3
  # The Agile Proxy module is a common namespace for all classes / sub modules.
4
4
  module AgileProxy
5
- VERSION = '0.1.20'
5
+ VERSION = '0.1.21'
6
6
  end
@@ -10,6 +10,7 @@ RSpec.configure do |config|
10
10
  config.before :all, :type => :integration do
11
11
  start_test_servers
12
12
  start_proxy_server
13
+ debug_me = true
13
14
  end
14
15
 
15
16
  end
@@ -1,23 +1,80 @@
1
- require 'eventmachine'
2
- require 'thin'
3
1
  require 'faraday'
4
2
  require 'agile_proxy/cli'
3
+ require 'socket'
4
+
5
+
5
6
 
6
- module Thin
7
- module Backends
8
- class TcpServer
9
- def get_port
10
- # seriously, eventmachine, how hard does getting a port have to be?
11
- Socket.unpack_sockaddr_in(EM.get_sockname(@signature)).first
12
- end
13
- end
14
- end
15
- end
16
7
 
17
8
  module AgileProxy
18
9
  module TestServer
10
+ class DummyApi
11
+ def response(env)
12
+ [200, {}, "hello!"]
13
+ end
14
+ end
15
+ class Server
16
+ attr_accessor :server_port
17
+ def initialize(world)
18
+ @world = world
19
+ at_exit do
20
+ cleanup
21
+ end
22
+ #Thin::Logging.silent = true
23
+ end
24
+ def pids
25
+ @pids ||= []
26
+ end
27
+ def cleanup
28
+ until pids.empty?
29
+ begin
30
+ Process.kill('INT', pids.pop);
31
+ rescue Errno::ESRCH
32
+ #Do nothing
33
+ end
34
+ end
35
+ end
36
+ def available_port(qty = 1)
37
+ # use Addrinfo
38
+ results = []
39
+ sockets_opened = []
40
+ while results.length < qty
41
+ socket = Socket.new(:INET, :STREAM, 0)
42
+ socket.bind(Addrinfo.tcp("127.0.0.1", 0))
43
+ port = socket.local_address.ip_port
44
+ results.push port unless results.include? port
45
+ sockets_opened.push socket
46
+ end
47
+ sockets_opened.each do |socket|
48
+ socket.close
49
+ end
50
+ results
51
+ end
52
+
53
+ def ruby
54
+ RbConfig.ruby
55
+ end
56
+ def start_test_servers
57
+ ports = available_port(3)
58
+ puts "Starting test server on #{ports[0]}"
59
+ pids.push spawn(ruby, "echo_server.rb", '--address', 'localhost', '--port', "#{ports[0]}")
60
+ puts "Starting test server on #{ports[1]}"
61
+ pids.push spawn(ruby, "echo_server.rb", '--address', 'localhost', '--port', "#{ports[1]}", '--ssl')
62
+ puts "Starting test server on #{ports[2]}"
63
+ pids.push spawn({'STATUS_CODE' => '500'}, ruby, "echo_server.rb", '--address', 'localhost', '--port', "#{ports[2]}")
64
+ @world.instance_eval do
65
+ @http_url = "http://localhost:#{ports.shift}"
66
+ @https_url = "https://localhost:#{ports.shift}"
67
+ @error_url = "http://localhost:#{ports.shift}"
68
+ @http_url_no_proxy = "http://localhost:#{server_port}"
69
+ @https_url_no_proxy = "https://localhost:#{server_port}"
70
+ end
71
+ end
72
+
73
+
74
+ end
75
+
19
76
  def initialize(rspecParams=nil)
20
- Thin::Logging.silent = true
77
+
21
78
  end
22
79
  def proxy_port
23
80
  3101
@@ -29,66 +86,20 @@ module AgileProxy
29
86
  3022
30
87
  end
31
88
 
32
- def start_test_servers
33
- q = Queue.new
34
- Thread.new do
35
- EM.run do
36
- echo = echo_app_setup
37
-
38
- http_server = start_server(echo)
39
- q.push http_server.backend.get_port
40
89
 
41
- https_server = start_server(echo, true)
42
- q.push https_server.backend.get_port
43
-
44
- echo_error = echo_app_setup(500)
45
- error_server = start_server(echo_error)
46
- q.push error_server.backend.get_port
47
- end
48
- end
49
-
50
- @http_url = "http://localhost:#{q.pop}"
51
- @https_url = "https://localhost:#{q.pop}"
52
- @error_url = "http://localhost:#{q.pop}"
53
- @http_url_no_proxy = "http://localhost:#{server_port}"
54
- @https_url_no_proxy = "https://localhost:#{server_port}"
90
+ def start_test_servers
91
+ @test_servers = Server.new(self)
92
+ @test_servers.server_port = server_port
93
+ @test_servers.start_test_servers
55
94
  end
56
95
 
57
96
  def start_proxy_server
58
97
  Thread.new do
59
98
  cli = Cli.start(['start', proxy_port.to_s, server_port.to_s, api_port.to_s, '--env', 'test'])
60
99
  end
61
- sleep 1
100
+ sleep 10
62
101
  end
63
102
 
64
- def echo_app_setup(response_code = 200)
65
- counter = 0
66
- proc do |env|
67
- req_body = env['rack.input'].read
68
- request_info = "#{env['REQUEST_METHOD']} #{env['PATH_INFO']}"
69
- res_body = request_info
70
- res_body += "\n#{req_body}" unless req_body.empty?
71
- counter += 1
72
- [
73
- response_code,
74
- { 'HTTP-X-EchoServer' => request_info,
75
- 'HTTP-X-EchoCount' => "#{counter}" },
76
- [res_body]
77
- ]
78
- end
79
- end
80
103
 
81
- def start_server(echo, ssl = false)
82
- http_server = Thin::Server.new '127.0.0.1', 0, echo
83
- if ssl
84
- http_server.ssl = true
85
- http_server.ssl_options = {
86
- private_key_file: File.expand_path('../../fixtures/test-server.key', __FILE__),
87
- cert_chain_file: File.expand_path('../../fixtures/test-server.crt', __FILE__)
88
- }
89
- end
90
- http_server.start
91
- http_server
92
- end
93
104
  end
94
105
  end