proxy-server 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ .idea
2
+ .bundle
3
+ coverage
4
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,54 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ proxy-server (0.0.1)
5
+ httpclient
6
+ json (>= 1.4.6)
7
+ sinatra (>= 1.2.6)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ addressable (2.2.6)
13
+ crack (0.3.1)
14
+ diff-lcs (1.1.3)
15
+ httpclient (2.2.1)
16
+ json (1.6.1)
17
+ multi_json (1.0.3)
18
+ rack (1.3.4)
19
+ rack-protection (1.1.4)
20
+ rack
21
+ rack-test (0.6.1)
22
+ rack (>= 1.0)
23
+ rake (0.9.2)
24
+ rspec (2.6.0)
25
+ rspec-core (~> 2.6.0)
26
+ rspec-expectations (~> 2.6.0)
27
+ rspec-mocks (~> 2.6.0)
28
+ rspec-core (2.6.4)
29
+ rspec-expectations (2.6.0)
30
+ diff-lcs (~> 1.1.2)
31
+ rspec-mocks (2.6.0)
32
+ simplecov (0.5.4)
33
+ multi_json (~> 1.0.3)
34
+ simplecov-html (~> 0.5.3)
35
+ simplecov-html (0.5.3)
36
+ sinatra (1.3.1)
37
+ rack (>= 1.3.4, ~> 1.3)
38
+ rack-protection (>= 1.1.2, ~> 1.1)
39
+ tilt (>= 1.3.3, ~> 1.3)
40
+ tilt (1.3.3)
41
+ webmock (1.7.6)
42
+ addressable (~> 2.2, > 2.2.5)
43
+ crack (>= 0.1.7)
44
+
45
+ PLATFORMS
46
+ ruby
47
+
48
+ DEPENDENCIES
49
+ proxy-server!
50
+ rack-test (>= 0.5.7)
51
+ rake (>= 0.9.2)
52
+ rspec (>= 2.6.0)
53
+ simplecov (>= 0.4.2)
54
+ webmock
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require 'rspec/core/rake_task'
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ task :coverage do
7
+ require 'simplecov'
8
+ require 'rspec/core'
9
+
10
+ SimpleCov.start do
11
+ add_group "lib", "lib"
12
+ end
13
+ SimpleCov.start
14
+ RSpec::Core::Runner.run %w[spec]
15
+ end
16
+
17
+
18
+ require 'rake/clean'
19
+ CLEAN.include %w(**/*.{log,pyc,rbc,tgz} doc)
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'proxy-server'
3
+ require 'rest_client' # you will need to install this via gem install rest-client / bundler etc
4
+ require 'json'
5
+
6
+ ENV.clear
7
+
8
+ Thread.new do
9
+ ProxyManager.run! :port => 4983
10
+ end
11
+
12
+ until_proxy_is_running = 2
13
+ sleep until_proxy_is_running # need to implement the ability to wait for the proxy to be running
14
+
15
+ proxy = JSON.parse(RestClient.post 'http://localhost:4983/proxies', {:proxy => 'http://www-cache.reith.bbc.co.uk:80'})
16
+
17
+ sleep until_proxy_is_running
18
+
19
+ RestClient.post "http://localhost:4983/proxies/#{proxy['port']}/requests", {:track => 'google.com'}
20
+
21
+ client = HTTPClient.new :proxy => "http://localhost:#{proxy['port']}"
22
+ client.get 'http://www.google.com'
23
+ client.get 'http://github.com'
24
+
25
+ p JSON.parse(HTTPClient.get("http://localhost:4983/proxies/#{proxy['port']}/requests").body)
26
+
27
+
28
+
@@ -0,0 +1,70 @@
1
+ require_relative './proxy_server'
2
+ require 'sinatra/base'
3
+ require 'json'
4
+
5
+ class ProxyManager < Sinatra::Base
6
+ START_PORT = 5000
7
+
8
+ attr_reader :running_proxy_servers, :assigned_proxy_ports
9
+ disable :show_exceptions
10
+
11
+ def initialize()
12
+ @running_proxy_servers = {}
13
+ @assigned_proxy_ports = []
14
+ super
15
+ end
16
+
17
+ get '/proxies' do
18
+ assigned_proxy_ports.to_json
19
+ end
20
+
21
+ post '/proxies' do
22
+ new_proxy_port = assigned_proxy_ports.max
23
+ new_proxy_port += 1 unless new_proxy_port.nil?
24
+ new_proxy_port ||= START_PORT
25
+
26
+ assigned_proxy_ports << new_proxy_port
27
+
28
+ options = {
29
+ :port => new_proxy_port
30
+ }
31
+
32
+ options[:proxy] = params[:proxy] if params[:proxy]
33
+ start_proxy(options)
34
+
35
+ {:port => new_proxy_port}.to_json
36
+ end
37
+
38
+ delete '/proxies' do
39
+ assigned_proxy_ports.clear
40
+ end
41
+
42
+ post '/proxies/:port/requests' do |port|
43
+ proxy_server = get_proxy(port.to_i)
44
+ proxy_server.track_request(params[:track])
45
+ end
46
+
47
+ get '/proxies/:port/requests' do |port|
48
+ proxy_server = get_proxy(port.to_i)
49
+ proxy_server.requests.to_json
50
+ end
51
+
52
+ post '/proxies/:port/requests/substitute' do |port|
53
+ proxy_server = get_proxy(port.to_i)
54
+ options = {}
55
+ options[:body] = params[:body] if params[:body]
56
+ options[:url] = params[:url] if params[:url]
57
+ proxy_server.substitute_request(params[:pattern], options)
58
+ end
59
+
60
+ def get_proxy(port)
61
+ running_proxy_servers[port]
62
+ end
63
+
64
+ def start_proxy(options)
65
+ proxy_server = ProxyServer.new(options)
66
+ proxy_server.run
67
+ running_proxy_servers[options[:port]] = proxy_server
68
+ end
69
+ end
70
+
@@ -0,0 +1,104 @@
1
+ require 'rack'
2
+ require 'httpclient'
3
+
4
+ class ProxyServer
5
+
6
+ attr_reader :upstream_proxy, :port
7
+ attr_reader :requests
8
+
9
+ DEFAULT_PORT = 8080
10
+
11
+ def initialize(options = {})
12
+ @upstream_proxy = options[:proxy]
13
+ @client = create_http_client
14
+
15
+ @port = options.fetch(:port, DEFAULT_PORT)
16
+
17
+ @substitute_requests = {}
18
+ @requests = []
19
+ @track_requests = []
20
+ end
21
+
22
+ def create_http_client
23
+ HTTPClient.new :proxy => @upstream_proxy
24
+ end
25
+
26
+ def run
27
+ Thread.new do
28
+ @handler = Rack::Handler::WEBrick
29
+
30
+ @handler.run self, :Port => self.port
31
+ end
32
+ end
33
+
34
+ def call(env)
35
+ log_request env
36
+
37
+ response = get_substitution(env)
38
+ return response unless response.nil?
39
+
40
+ method = env['REQUEST_METHOD']
41
+ uri = "http://#{env['HTTP_HOST']}#{env['PATH_INFO']}"
42
+ params = get_params(env['QUERY_STRING'])
43
+ body = get_request_body(env)
44
+ headers = get_request_headers(env)
45
+ response = @client.request(method, uri, params, body, headers)
46
+
47
+ [ response.status, response.headers, [response.body] ]
48
+ end
49
+
50
+ def get_substitution(env)
51
+ uri = env['REQUEST_URI'] || "http://#{env['SERVER_NAME']}#{env['PATH_INFO']}#{env['QUERY_STRING'] ? '?'+env['QUERY_STRING'] : ''}"
52
+ @substitute_requests.each do |pattern, options|
53
+ if Regexp.new(pattern) =~ uri
54
+ return get_substituted_response(options)
55
+ end
56
+ end
57
+ nil
58
+ end
59
+
60
+ def get_substituted_response(options)
61
+ if options[:body]
62
+ [ 200, {}, [options[:body]] ]
63
+ elsif options[:url]
64
+ response = @client.get(options[:url])
65
+ [ response.status, response.headers, [response.body] ]
66
+ end
67
+ end
68
+
69
+ def substitute_request(pattern, options)
70
+ @substitute_requests[pattern] = options
71
+ end
72
+
73
+ def track_request(pattern)
74
+ @track_requests << pattern
75
+ end
76
+
77
+ def get_params(query_string)
78
+ query_string.split('&').inject({}) do |hsh, i|
79
+ kv = i.split('='); hsh[kv[0]] = kv[1]; hsh
80
+ end unless query_string.nil? or query_string.length == 0
81
+ end
82
+
83
+ def log_request(env)
84
+
85
+ url = env['REQUEST_URI'] || "http://#{env['SERVER_NAME']}#{env['PATH_INFO']}#{env['QUERY_STRING'].length>0 ? '?'+env['QUERY_STRING'] : ''}"
86
+ @track_requests.each do |pattern|
87
+ @requests << url if Regexp.new(pattern) =~ url
88
+ end
89
+ end
90
+
91
+ private
92
+ def get_request_body(env)
93
+ body = ''
94
+ env['rack.input'].each_line {|string| body << string }
95
+ body
96
+ end
97
+
98
+ def get_request_headers(env)
99
+ headers = {}
100
+ env.each {|k,v| if k =~ /HTTP_(\w+)/ then headers[$1] = v end }
101
+ headers
102
+ end
103
+ end
104
+
@@ -0,0 +1,2 @@
1
+ require_relative './proxy/proxy_server'
2
+ require_relative './proxy/proxy_manager'
@@ -0,0 +1,32 @@
1
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'proxy-server'
5
+ s.version = '0.0.1'
6
+ s.authors = ["Derek Ekins"]
7
+ s.description = 'Proxy server'
8
+ s.summary = "proxy-server-#{s.version}"
9
+ s.email = 'derek@spathi.com'
10
+ s.homepage = "http://github.com/dereke/proxy-server"
11
+
12
+ s.platform = Gem::Platform::RUBY
13
+
14
+ s.add_dependency 'json', '>= 1.4.6'
15
+ s.add_dependency 'sinatra', '>= 1.2.6'
16
+ s.add_dependency 'httpclient'
17
+
18
+ s.add_development_dependency 'rake', '>= 0.9.2'
19
+ s.add_development_dependency 'rspec', '>= 2.6.0'
20
+ s.add_development_dependency 'simplecov', '>= 0.4.2'
21
+ s.add_development_dependency 'webmock'
22
+
23
+
24
+ s.add_development_dependency 'rack-test', '>= 0.5.7'
25
+
26
+ s.rubygems_version = ">= 1.6.1"
27
+ s.files = `git ls-files`.split("\n")
28
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
29
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
30
+ s.rdoc_options = ["--charset=UTF-8"]
31
+ s.require_path = "lib"
32
+ end
@@ -0,0 +1,77 @@
1
+ require_relative '../spec_helper'
2
+ require_relative '../../lib/proxy/proxy_manager'
3
+ require 'rack/test'
4
+ require 'webmock/rspec'
5
+
6
+ describe ProxyManager do
7
+ include Rack::Test::Methods
8
+
9
+ before do
10
+ @proxy_server = Object.new
11
+ ProxyManager.any_instance.stub(:start_proxy).with(anything()).and_return(@proxy_server)
12
+ ProxyManager.any_instance.stub(:get_proxy).with(anything()).and_return(@proxy_server)
13
+ end
14
+
15
+ let(:app) { ProxyManager.new }
16
+
17
+ it "should create a new proxy when I ask for one" do
18
+ response = post '/proxies'
19
+ proxy = JSON.parse(response.body)
20
+ proxy.should == {'port' => ProxyManager::START_PORT}
21
+ end
22
+
23
+ it "should create a new proxy with an upstream proxy when asked to" do
24
+ ProxyManager.any_instance.should_receive(:start_proxy).with(hash_including(:proxy => 'http://my_proxy:80'))
25
+ response = post '/proxies', {:proxy => 'http://my_proxy:80'}
26
+ end
27
+
28
+ it "should tell me about all the proxies that have been created" do
29
+ post '/proxies'
30
+ response = get '/proxies'
31
+ JSON.parse(response.body).should == [ProxyManager::START_PORT]
32
+ end
33
+
34
+ it "should remove all proxies when asked" do
35
+ post '/proxies'
36
+ delete '/proxies'
37
+
38
+ response = get '/proxies'
39
+ JSON.parse(response.body).should == []
40
+ end
41
+
42
+ it "should assign new proxy ports when more than one is asked for" do
43
+ first_expected_proxy = ProxyManager::START_PORT
44
+ second_expected_proxy = ProxyManager::START_PORT + 1
45
+
46
+ first_response = post '/proxies'
47
+ second_response = post '/proxies'
48
+
49
+ JSON.parse(first_response.body)['port'].should == first_expected_proxy
50
+ JSON.parse(second_response.body)['port'].should == second_expected_proxy
51
+ end
52
+
53
+ it "ads a given url to a list of them to track" do
54
+ track_url = 'public/.*.js'
55
+
56
+ @proxy_server.should_receive(:track_request).with(track_url)
57
+ post "/proxies/1111/requests", {:track => track_url}
58
+ end
59
+
60
+ it "ads a given url to a list of them to track" do
61
+ @proxy_server.stub!(:requests).and_return(['request 1', 'request 2'])
62
+ response = get "/proxies/1111/requests"
63
+ requests = JSON.parse(response.body)
64
+ requests.should include('request 1')
65
+ requests.should include('request 2')
66
+ end
67
+
68
+ it "can substitute a request with another body" do
69
+ @proxy_server.should_receive(:substitute_request).with('*.js', :body => 'alert(1);')
70
+ post "/proxies/1111/requests/substitute", {:pattern => '*.js', :body => 'alert(1);'}
71
+ end
72
+
73
+ it "can substitute a request with another url" do
74
+ @proxy_server.should_receive(:substitute_request).with('*.js', :url => 'http://example.com/test.js')
75
+ post "/proxies/1111/requests/substitute", {:pattern => '*.js', :url => 'http://example.com/test.js'}
76
+ end
77
+ end
@@ -0,0 +1,81 @@
1
+ require_relative '../spec_helper'
2
+ require_relative '../../lib/proxy/proxy_server'
3
+ require 'rack/test'
4
+ require 'webmock/rspec'
5
+
6
+ describe ProxyServer do
7
+ include Rack::Test::Methods
8
+ before do
9
+ ENV.clear
10
+ end
11
+
12
+ let(:app) { ProxyServer.new }
13
+
14
+ it "can be configured with an upstream proxy" do
15
+ proxy_uri = 'http://test-proxy:80'
16
+ proxy = ProxyServer.new :proxy => proxy_uri
17
+ proxy.upstream_proxy.should == proxy_uri
18
+ end
19
+
20
+ it "can be configured to run on a specific port" do
21
+ proxy_port = 8080
22
+ proxy = ProxyServer.new :port => proxy_port
23
+ proxy.port.should == proxy_port
24
+ end
25
+
26
+ it "default the port when none is specified" do
27
+ proxy = ProxyServer.new
28
+ proxy.port.should == ProxyServer::DEFAULT_PORT
29
+ end
30
+
31
+ it "should allow requests" do
32
+ stub_request(:get, "http://www.example.com")
33
+
34
+ response = get 'http://www.example.com'
35
+ response.status.should == 200
36
+ end
37
+
38
+ it "should allow requests with query strings" do
39
+ stub_request(:get, "http://www.example.com?para=value")
40
+
41
+ response = get "http://www.example.com?para=value"
42
+ response.status.should == 200
43
+ end
44
+
45
+ it "can substitute the response of a request with a body of text" do
46
+ proxy = ProxyServer.new
47
+ expected_response = "this is not what you are looking for"
48
+ proxy.substitute_request '.*com', :body => expected_response
49
+
50
+ browser = Rack::Test::Session.new(Rack::MockSession.new(proxy))
51
+ response = browser.get 'http://www.google.com'
52
+ response.body.should == expected_response
53
+ end
54
+
55
+ it "can substitute the response of a request with another url to call" do
56
+ proxy = ProxyServer.new
57
+ substitute_url = "http://example.com"
58
+ expected_response_body = "substitute body"
59
+ stub_request(:get, substitute_url).to_return(:body => expected_response_body)
60
+ proxy.substitute_request '.*com', :url => substitute_url
61
+
62
+ browser = Rack::Test::Session.new(Rack::MockSession.new(proxy))
63
+ response = browser.get 'http://www.google.com'
64
+ response.body.should == expected_response_body
65
+ end
66
+
67
+ it "tracks a url that matches the pattern" do
68
+ proxy = ProxyServer.new
69
+ expected_response = "this is not what you are looking for"
70
+ proxy.track_request '.*com'
71
+
72
+ stub_request(:get, 'http://www.google.com/')
73
+ stub_request(:get, 'http://www.google.co.uk/')
74
+
75
+ browser = Rack::Test::Session.new(Rack::MockSession.new(proxy))
76
+ browser.get 'http://www.google.com/'
77
+ browser.get 'http://www.google.co.uk/'
78
+
79
+ proxy.requests.should include('http://www.google.com/')
80
+ end
81
+ end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup
4
+ require 'rspec'
5
+ ENV['RACK_ENV'] = 'test'
6
+
7
+ class String
8
+ alias each each_line
9
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: proxy-server
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Derek Ekins
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-10-13 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json
16
+ requirement: &12655120 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.4.6
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *12655120
25
+ - !ruby/object:Gem::Dependency
26
+ name: sinatra
27
+ requirement: &12654340 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 1.2.6
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *12654340
36
+ - !ruby/object:Gem::Dependency
37
+ name: httpclient
38
+ requirement: &12653840 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *12653840
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: &12653160 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.9.2
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *12653160
58
+ - !ruby/object:Gem::Dependency
59
+ name: rspec
60
+ requirement: &12652520 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: 2.6.0
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *12652520
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: &12651940 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: 0.4.2
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *12651940
80
+ - !ruby/object:Gem::Dependency
81
+ name: webmock
82
+ requirement: &12651440 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *12651440
91
+ - !ruby/object:Gem::Dependency
92
+ name: rack-test
93
+ requirement: &12650780 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: 0.5.7
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *12650780
102
+ description: Proxy server
103
+ email: derek@spathi.com
104
+ executables: []
105
+ extensions: []
106
+ extra_rdoc_files: []
107
+ files:
108
+ - .gitignore
109
+ - Gemfile
110
+ - Gemfile.lock
111
+ - Rakefile
112
+ - examples/proxy_in_process.rb
113
+ - lib/proxy-server.rb
114
+ - lib/proxy/proxy_manager.rb
115
+ - lib/proxy/proxy_server.rb
116
+ - proxy-server.gemspec
117
+ - spec/proxy/proxy_manager_spec.rb
118
+ - spec/proxy/proxy_server_spec.rb
119
+ - spec/spec_helper.rb
120
+ homepage: http://github.com/dereke/proxy-server
121
+ licenses: []
122
+ post_install_message:
123
+ rdoc_options:
124
+ - --charset=UTF-8
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ! '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 1.8.10
142
+ signing_key:
143
+ specification_version: 3
144
+ summary: proxy-server-0.0.1
145
+ test_files: []