webrick_httpreverseproxyserver 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +14 -0
- data/Rakefile +30 -0
- data/lib/webrick/httpreverseproxyserver.rb +162 -0
- data/lib/webrick/httpreverseproxyserver/version.rb +5 -0
- metadata +65 -0
data/README.rdoc
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
= HTTP Reverse proxy server
|
2
|
+
|
3
|
+
This library is not meant for production use. It is based on a snippet on
|
4
|
+
RubyForge and was packaged as gem to make it easily available.
|
5
|
+
|
6
|
+
Source: http://rubyforge.org/snippet/detail.php?type=snippet&id=117
|
7
|
+
|
8
|
+
|
9
|
+
You may use this class, to programmatically set up a quick and simple reverse
|
10
|
+
proxy. I found it useful to implement advanced inspection of an HTTP
|
11
|
+
communication between an uncontrolled client and server.
|
12
|
+
|
13
|
+
|
14
|
+
See WEBrick::HTTPReverseProxyServer for more information.
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
$: << File.expand_path('../lib', __FILE__)
|
6
|
+
require 'webrick/httpreverseproxyserver/version'
|
7
|
+
|
8
|
+
desc 'Generate documentation for the webrick_httpreverseproxyserver gem.'
|
9
|
+
Rake::RDocTask.new(:doc) do |doc|
|
10
|
+
doc.rdoc_dir = 'doc'
|
11
|
+
doc.title = 'WEBRick::HTTPReverseProxyServer'
|
12
|
+
doc.options << '--line-numbers' << '--inline-source'
|
13
|
+
doc.rdoc_files.include('README.rdoc')
|
14
|
+
doc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Build gem'
|
18
|
+
task :build do
|
19
|
+
sh 'gem build webrick_httpreverseproxyserver.gemspec'
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Install gem locally"
|
23
|
+
task :install => :build do
|
24
|
+
sh "gem install webrick_httpreverseproxyserver-#{WEBrick::HTTPReverseProxyServer::VERSION}.gem"
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Release gem'
|
28
|
+
task :release => :build do
|
29
|
+
sh "gem push webrick_httpreverseproxyserver-#{WEBrick::HTTPReverseProxyServer::VERSION}.gem"
|
30
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'webrick'
|
4
|
+
require 'net/http'
|
5
|
+
|
6
|
+
module WEBrick
|
7
|
+
# Proxy rule to configure WEBrick::HTTPReverseProxyServer
|
8
|
+
class ProxyRule < Struct.new(:pattern, :host, :port, :replacement)
|
9
|
+
end
|
10
|
+
|
11
|
+
# == Use case
|
12
|
+
#
|
13
|
+
# You have several services running as different users for security purposes
|
14
|
+
# (they might even be chrooted). In production we use apache but for testing
|
15
|
+
# I prefer to use webrick because I find it more flexible for unit testing.
|
16
|
+
#
|
17
|
+
#
|
18
|
+
# == Configuration
|
19
|
+
#
|
20
|
+
# The proxy mapping is modelled on the ProxyPass directive of apache. For
|
21
|
+
# example:
|
22
|
+
#
|
23
|
+
# original URL proxies private URL
|
24
|
+
# ------------------------ ==> --------------------------
|
25
|
+
# /marmalade/index.html localhost:8081/index.html
|
26
|
+
# /apps/vegemite?id=123 localhost:8082/apps/someservlet?id=123
|
27
|
+
#
|
28
|
+
# Its not designed to be mod_rewrite (eg. query_string cannot be
|
29
|
+
# transformed), but you can specify proxy rules that match a fragment of the
|
30
|
+
# original URL and replace it with something else while also sending the new
|
31
|
+
# URL to the proxied host and port. So the rules in that example are
|
32
|
+
# specified thus:
|
33
|
+
#
|
34
|
+
# serverConfig = {
|
35
|
+
# :Port => 80,
|
36
|
+
# :ProxyRules => [
|
37
|
+
# WEBrick::ProxyRule.new('^/marmalade/', 'localhost', 8081, '/'),
|
38
|
+
# WEBrick::ProxyRule.new('vegemite', 'localhost', 8082, 'someservlet')
|
39
|
+
# ]
|
40
|
+
# }
|
41
|
+
# server = WEBrick::HTTPReverseProxyServer.new(serverConfig)
|
42
|
+
#
|
43
|
+
# ProxyRules is an array so the order is important - the first match is used!
|
44
|
+
# If no matches are found then the URL is handled by the local web server
|
45
|
+
# normally.
|
46
|
+
#
|
47
|
+
#
|
48
|
+
# == Running a server
|
49
|
+
#
|
50
|
+
# You may start a server, just like any WEBrick server.
|
51
|
+
#
|
52
|
+
# To get started using RubyGems, use the following example:
|
53
|
+
#
|
54
|
+
# require 'rubygems'
|
55
|
+
# require 'webrick/httpreverseproxyserver'
|
56
|
+
#
|
57
|
+
# # create a configuration and a server instance
|
58
|
+
# serverConfig = {
|
59
|
+
# :Port => 8080,
|
60
|
+
# :ProxyRules => [WEBrick::ProxyRule.new('/', 'www.example.com', 80, '/')]
|
61
|
+
# }
|
62
|
+
# server = WEBrick::HTTPReverseProxyServer.new(serverConfig)
|
63
|
+
#
|
64
|
+
# # catch ^C to quit cleanly
|
65
|
+
# trap("INT") { server.shutdown }
|
66
|
+
#
|
67
|
+
# # start request-response-loop
|
68
|
+
# server.start
|
69
|
+
#
|
70
|
+
#
|
71
|
+
# == Advanced inspection
|
72
|
+
#
|
73
|
+
# In order to better analyse an HTTP stream, you may easily subclass
|
74
|
+
# HTTPReverseProxyServer to add advanced request/response inspection.
|
75
|
+
#
|
76
|
+
# The following example implements basic Cookie logging:
|
77
|
+
#
|
78
|
+
# class CookieLoggingProxy < WEBrick::HTTPReverseProxyServer
|
79
|
+
# def service(request, response)
|
80
|
+
# super.tap do
|
81
|
+
# puts
|
82
|
+
# puts request.request_line
|
83
|
+
# print_cookie_headers request.header
|
84
|
+
# puts response.status_line
|
85
|
+
# print_cookie_headers response.header
|
86
|
+
# end
|
87
|
+
# end
|
88
|
+
#
|
89
|
+
# def print_cookie_headers(headers)
|
90
|
+
# headers.each do |key, val|
|
91
|
+
# puts "#{key}: #{val}" if key =~ /cookie/i
|
92
|
+
# end
|
93
|
+
# end
|
94
|
+
# end
|
95
|
+
class HTTPReverseProxyServer < HTTPServer
|
96
|
+
def service(request, response)
|
97
|
+
rule = first_matching_proxy_rule(request)
|
98
|
+
if rule.nil?
|
99
|
+
super(request, response)
|
100
|
+
else
|
101
|
+
service_proxy(request, response, rule)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
protected
|
106
|
+
# find the *first* matching pattern in the proxy map
|
107
|
+
def first_matching_proxy_rule(request)
|
108
|
+
matching_rul = @config[:ProxyRules].detect { |rule|
|
109
|
+
re = Regexp.new(rule.pattern)
|
110
|
+
m = re.match(request.path)
|
111
|
+
not m.nil?
|
112
|
+
}
|
113
|
+
return(matching_rule)
|
114
|
+
end
|
115
|
+
|
116
|
+
def service_proxy(request, response, rule)
|
117
|
+
host, port, path = map_to_proxyURI(request, rule)
|
118
|
+
# convert WEBrick header (values wrapped in an array) into Net::HTTP
|
119
|
+
# header (simple values)
|
120
|
+
header = {}
|
121
|
+
request.header.keys { |key| header[key] = request.header[key][0] }
|
122
|
+
header['x-forwarded-for'] = request.peeraddr[2] # the name of the requesting host
|
123
|
+
# send the new request to the private server (hacked from WEBrick::HTTPProxyServer)
|
124
|
+
response = nil
|
125
|
+
begin
|
126
|
+
http = Net::HTTP.new(host, port)
|
127
|
+
http.start {
|
128
|
+
case request.request_method
|
129
|
+
when "GET" then response = http.get(path, header)
|
130
|
+
when "POST" then response = http.post(path, request.body || "", header)
|
131
|
+
when "HEAD" then response = http.head(path, header)
|
132
|
+
else
|
133
|
+
raise HTTPStatus::MethodNotAllowed,
|
134
|
+
"unsupported method `#{request.request_method}'."
|
135
|
+
end
|
136
|
+
}
|
137
|
+
rescue => err
|
138
|
+
logger.debug("#{err.class}: #{err.message}")
|
139
|
+
raise HTTPStatus::ServiceUnavailable, err.message
|
140
|
+
end
|
141
|
+
response['connection'] = "close"
|
142
|
+
|
143
|
+
# Convert Net::HTTP::HTTPResponse to WEBrick::HTTPResponse
|
144
|
+
response.status = response.code.to_i
|
145
|
+
response.each { |key, val| response[key] = val }
|
146
|
+
response.body = response.body
|
147
|
+
|
148
|
+
# Process contents
|
149
|
+
if handler = @config[:ProxyContentHandler]
|
150
|
+
handler.call(request, response)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def map_to_proxyURI(request, rule)
|
155
|
+
path = (request.path).sub(%r!#{rule.pattern}!, rule.replacement)
|
156
|
+
path += '?' + request.query_string if request.query_string
|
157
|
+
return([rule.host, rule.port, path])
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
require 'webrick/httpreverseproxyserver/version'
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: webrick_httpreverseproxyserver
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Gregor Schmidt
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-07-22 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Implements a simple reverse HTTP proxy - useful for advanced configuration or inspection of reverse proxies in development.
|
22
|
+
email: g.schmidt@finn.de
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- lib/webrick/httpreverseproxyserver/version.rb
|
31
|
+
- lib/webrick/httpreverseproxyserver.rb
|
32
|
+
- Rakefile
|
33
|
+
- README.rdoc
|
34
|
+
has_rdoc: true
|
35
|
+
homepage: http://github.com/finnlabs/webrick_httpreverseproxyserver
|
36
|
+
licenses: []
|
37
|
+
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
segments:
|
48
|
+
- 0
|
49
|
+
version: "0"
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project: "[none]"
|
60
|
+
rubygems_version: 1.3.6
|
61
|
+
signing_key:
|
62
|
+
specification_version: 3
|
63
|
+
summary: Implements a simple reverse HTTP proxy server
|
64
|
+
test_files: []
|
65
|
+
|