1
1
require "net/http"
2
2
require "net/https"
3
3
require "rack-proxy"
4
+ require "rack_reverse_proxy/roundtrip"
4
5
5
6
module RackReverseProxy
6
- # FIXME: Enable them and fix issues during refactoring
7
- # rubocop:disable Metrics/ClassLength
8
- # rubocop:disable Metrics/MethodLength
9
- # rubocop:disable Metrics/CyclomaticComplexity
10
- # rubocop:disable Metrics/PerceivedComplexity
11
- # rubocop:disable Metrics/AbcSize
12
-
13
7
# Rack middleware for handling reverse proxying
14
8
class Middleware
15
9
include NewRelic ::Agent ::Instrumentation ::ControllerInstrumentation if defined? NewRelic
@@ -27,122 +21,11 @@ def initialize(app = nil, &b)
27
21
end
28
22
29
23
def call ( env )
30
- rackreq = Rack ::Request . new ( env )
31
- rule = get_rule (
32
- rackreq . fullpath ,
33
- Rack ::Proxy . extract_http_request_headers ( rackreq . env ) ,
34
- rackreq
35
- )
36
- return @app . call ( env ) if rule . nil?
37
-
38
- if @global_options [ :newrelic_instrumentation ]
39
- # Rack::ReverseProxy/foo/bar#GET
40
- action_path = rackreq . path . gsub ( %r{/\d +} , "/:id" ) . gsub ( %r{^/} , "" )
41
- action_name = "#{ action_path } /#{ rackreq . request_method } "
42
- perform_action_with_newrelic_trace ( :name => action_name , :request => rackreq ) do
43
- proxy ( env , rackreq , rule )
44
- end
45
- else
46
- proxy ( env , rackreq , rule )
47
- end
24
+ RoundTrip . new ( @app , env , @global_options , @rules ) . call
48
25
end
49
26
50
27
private
51
28
52
- def proxy ( env , source_request , rule )
53
- uri = rule . get_uri (
54
- source_request . fullpath ,
55
- env ,
56
- Rack ::Proxy . extract_http_request_headers ( source_request . env ) ,
57
- source_request
58
- )
59
- return @app . call ( env ) if uri . nil?
60
-
61
- options = @global_options . dup . merge ( rule . options )
62
-
63
- if options [ :force_ssl ] && options [ :replace_response_host ] &&
64
- source_request . scheme == "http"
65
- rewrite_uri ( uri , source_request )
66
- uri . scheme = "https"
67
- return [ 301 , { "Location" => uri . to_s } , "" ]
68
- end
69
-
70
- # Initialize request
71
- target_request = Net ::HTTP . const_get (
72
- source_request . request_method . capitalize
73
- ) . new ( uri . request_uri )
74
-
75
- # Setup headers
76
- target_request_headers = Rack ::Proxy . extract_http_request_headers ( source_request . env )
77
-
78
- if options [ :preserve_host ]
79
- if uri . port == uri . default_port
80
- target_request_headers [ "HOST" ] = uri . host
81
- else
82
- target_request_headers [ "HOST" ] = "#{ uri . host } :#{ uri . port } "
83
- end
84
- end
85
-
86
- if options [ :x_forwarded_host ]
87
- target_request_headers [ "X-Forwarded-Host" ] = source_request . host
88
- target_request_headers [ "X-Forwarded-Port" ] = "#{ source_request . port } "
89
- end
90
-
91
- target_request . initialize_http_header ( target_request_headers )
92
-
93
- # Basic auth
94
- if options [ :username ] && options [ :password ]
95
- target_request . basic_auth options [ :username ] , options [ :password ]
96
- end
97
-
98
- # Setup body
99
- if target_request . request_body_permitted? && source_request . body
100
- source_request . body . rewind
101
- target_request . body_stream = source_request . body
102
- end
103
-
104
- target_request . content_length = source_request . content_length || 0
105
- target_request . content_type = source_request . content_type if source_request . content_type
106
-
107
- # Create a streaming response (the actual network communication is deferred, a.k.a. streamed)
108
- target_response = Rack ::HttpStreamingResponse . new ( target_request , uri . host , uri . port )
109
-
110
- # pass the timeout configuration through
111
- target_response . read_timeout = options [ :timeout ] if options [ :timeout ] . to_i > 0
112
-
113
- target_response . use_ssl = "https" == uri . scheme
114
-
115
- # Let rack set the transfer-encoding header
116
- response_headers = Rack ::Utils ::HeaderHash . new (
117
- Rack ::Proxy . normalize_headers ( format_headers ( target_response . headers ) )
118
- )
119
- response_headers . delete ( "Transfer-Encoding" )
120
- response_headers . delete ( "Status" )
121
-
122
- # Replace the location header with the proxy domain
123
- if response_headers [ "Location" ] && options [ :replace_response_host ]
124
- response_location = URI ( response_headers [ "location" ] )
125
- rewrite_uri ( response_location , source_request )
126
- response_headers [ "Location" ] = response_location . to_s
127
- end
128
-
129
- [ target_response . status , response_headers , target_response . body ]
130
- end
131
-
132
- def get_rule ( path , headers , rackreq )
133
- matches = @rules . select do |rule |
134
- rule . proxy? ( path , headers , rackreq )
135
- end
136
-
137
- if matches . length < 1
138
- nil
139
- elsif matches . length > 1 && @global_options [ :matching ] != :first
140
- fail Errors ::AmbiguousMatch . new ( path , matches )
141
- else
142
- matches . first
143
- end
144
- end
145
-
146
29
def reverse_proxy_options ( options )
147
30
@global_options = options
148
31
end
@@ -153,23 +36,5 @@ def reverse_proxy(rule, url = nil, opts = {})
153
36
end
154
37
@rules << Rule . new ( rule , url , opts )
155
38
end
156
-
157
- def format_headers ( headers )
158
- headers . inject ( { } ) do |acc , ( key , val ) |
159
- formated_key = key . split ( "-" ) . map ( &:capitalize ) . join ( "-" )
160
- acc [ formated_key ] = Array ( val )
161
- acc
162
- end
163
- end
164
-
165
- def request_default_port? ( req )
166
- [ [ "http" , 80 ] , [ "https" , 443 ] ] . include? ( [ req . scheme , req . port ] )
167
- end
168
-
169
- def rewrite_uri ( uri , original_req )
170
- uri . scheme = original_req . scheme
171
- uri . host = original_req . host
172
- uri . port = original_req . port unless request_default_port? ( original_req )
173
- end
174
39
end
175
40
end
0 commit comments