Skip to content

Commit e509a93

Browse files
committed
Merge pull request jaswope#20 from waterlink/refactoring
Major refactoring of Middleware => RoundTrip
2 parents a0138f8 + 3a4e287 commit e509a93

File tree

2 files changed

+279
-137
lines changed

2 files changed

+279
-137
lines changed
Lines changed: 2 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
require "net/http"
22
require "net/https"
33
require "rack-proxy"
4+
require "rack_reverse_proxy/roundtrip"
45

56
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-
137
# Rack middleware for handling reverse proxying
148
class Middleware
159
include NewRelic::Agent::Instrumentation::ControllerInstrumentation if defined? NewRelic
@@ -27,122 +21,11 @@ def initialize(app = nil, &b)
2721
end
2822

2923
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
4825
end
4926

5027
private
5128

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-
14629
def reverse_proxy_options(options)
14730
@global_options = options
14831
end
@@ -153,23 +36,5 @@ def reverse_proxy(rule, url = nil, opts = {})
15336
end
15437
@rules << Rule.new(rule, url, opts)
15538
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
17439
end
17540
end

0 commit comments

Comments
 (0)