@@ -5,24 +5,25 @@ module Rack
5
5
class ReverseProxy
6
6
def initialize ( app = nil , &b )
7
7
@app = app || lambda { [ 404 , [ ] , [ ] ] }
8
- @paths = { }
9
- @opts = { :preserve_host => false }
8
+ @matchers = [ ]
9
+ @global_options = { }
10
10
instance_eval &b if block_given?
11
11
end
12
12
13
13
def call ( env )
14
14
rackreq = Rack ::Request . new ( env )
15
- matcher , url = get_matcher_and_url rackreq . fullpath
15
+ matcher = get_matcher rackreq . fullpath
16
16
return @app . call ( env ) if matcher . nil?
17
17
18
- uri = get_uri ( url , matcher , rackreq . fullpath )
18
+ uri = matcher . get_uri ( rackreq . fullpath )
19
+ all_opts = matcher . options #TODO: merge with global opts
19
20
headers = Rack ::Utils ::HeaderHash . new
20
21
env . each { |key , value |
21
22
if key =~ /HTTP_(.*)/
22
23
headers [ $1] = value
23
24
end
24
25
}
25
- headers [ 'HOST' ] = uri . host if @opts [ :preserve_host ]
26
+ headers [ 'HOST' ] = uri . host if all_opts [ :preserve_host ]
26
27
27
28
session = Net ::HTTP . new ( uri . host , uri . port )
28
29
session . use_ssl = ( uri . scheme == 'https' )
@@ -32,10 +33,10 @@ def call(env)
32
33
case m
33
34
when "GET" , "HEAD" , "DELETE" , "OPTIONS" , "TRACE"
34
35
req = Net ::HTTP . const_get ( m . capitalize ) . new ( uri . request_uri , headers )
35
- req . basic_auth @opts [ :username ] , @opts [ :password ] if @opts [ :username ] and @opts [ :password ]
36
+ req . basic_auth all_opts [ :username ] , all_opts [ :password ] if all_opts [ :username ] and all_opts [ :password ]
36
37
when "PUT" , "POST"
37
38
req = Net ::HTTP . const_get ( m . capitalize ) . new ( uri . request_uri , headers )
38
- req . basic_auth @opts [ :username ] , @opts [ :password ] if @opts [ :username ] and @opts [ :password ]
39
+ req . basic_auth all_opts [ :username ] , all_opts [ :password ] if all_opts [ :username ] and all_opts [ :password ]
39
40
req . content_length = rackreq . body . length
40
41
req . body_stream = rackreq . body
41
42
else
@@ -55,17 +56,17 @@ def call(env)
55
56
56
57
private
57
58
58
- def get_matcher_and_url path
59
- matches = @paths . select do |matcher , url |
60
- match_path ( path , matcher )
59
+ def get_matcher path
60
+ matches = @matchers . select do |matcher |
61
+ matcher . match? ( path )
61
62
end
62
63
63
64
if matches . length < 1
64
65
nil
65
66
elsif matches . length > 1
66
67
raise AmbiguousProxyMatch . new ( path , matches )
67
68
else
68
- matches . first . map { | a | a . dup }
69
+ matches . first
69
70
end
70
71
end
71
72
@@ -79,27 +80,10 @@ def create_response_headers http_response
79
80
response_headers
80
81
end
81
82
82
- def match_path ( path , matcher )
83
- if matcher . is_a? ( Regexp )
84
- path . match ( matcher )
85
- else
86
- path . match ( /^#{ matcher . to_s } / )
87
- end
88
- end
89
-
90
- def get_uri ( url , matcher , path )
91
- if url =~/\$ \d /
92
- match_path ( path , matcher ) . to_a . each_with_index { |m , i | url . gsub! ( "$#{ i . to_s } " , m ) }
93
- URI ( url )
94
- else
95
- URI . join ( url , path )
96
- end
97
- end
98
83
99
84
def reverse_proxy matcher , url , opts = { }
100
85
raise GenericProxyURI . new ( url ) if matcher . is_a? ( String ) && URI ( url ) . class == URI ::Generic
101
- @paths . merge! ( matcher => url )
102
- @opts . merge! ( opts )
86
+ @matchers << ReverseProxyMatcher . new ( matcher , url , opts )
103
87
end
104
88
end
105
89
@@ -129,8 +113,40 @@ def to_s
129
113
private
130
114
131
115
def formatted_matches
132
- matches . map { |m | %Q(" #{ m [ 0 ] . to_s } " => " #{ m [ 1 ] } ") } . join ( ', ' )
116
+ matches . map { |matcher | matcher . to_s } . join ( ', ' )
133
117
end
134
118
end
135
119
120
+ class ReverseProxyMatcher
121
+ def initialize ( matching , url , options )
122
+ @matching = matching
123
+ @url = url
124
+ @options = { :preserve_host => false } . merge ( options )
125
+ @matching_regexp = matching . kind_of? ( Regexp ) ? matching : /^#{ matching . to_s } /
126
+ end
127
+
128
+ attr_reader :matching , :matching_regexp , :url , :options
129
+
130
+ def match? ( path )
131
+ match_path ( path ) ? true : false
132
+ end
133
+
134
+ def get_uri ( path )
135
+ if url =~/\$ \d /
136
+ match_path ( path ) . to_a . each_with_index { |m , i | url . gsub! ( "$#{ i . to_s } " , m ) }
137
+ URI ( url )
138
+ else
139
+ URI . join ( url , path )
140
+ end
141
+ end
142
+ def to_s
143
+ %Q("#{ matching . to_s } " => "#{ url } ")
144
+ end
145
+ private
146
+ def match_path ( path )
147
+ path . match ( matching_regexp )
148
+ end
149
+
150
+
151
+ end
136
152
end
0 commit comments