Skip to content

Commit 3bb8094

Browse files
committed
Merge pull request jaswope#25 from waterlink/MrMarvin-openssl-verify-mode
Add openssl verify mode option
2 parents d866060 + 91583f7 commit 3bb8094

File tree

9 files changed

+123
-36
lines changed

9 files changed

+123
-36
lines changed

Gemfile

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ source "https://rubygems.org"
22

33
gemspec
44

5+
ruby_version = RUBY_VERSION.to_f
6+
rubocop_platform = [:ruby_20, :ruby_21, :ruby_22]
7+
rubocop_platform = [:ruby_20, :ruby_21] if ruby_version < 2.0
8+
59
group :test do
610
gem "rspec"
711
gem "rack-test"
812
gem "webmock"
9-
gem "rubocop", :platform => [:ruby_20, :ruby_21, :ruby_22]
13+
gem "rubocop", :platform => rubocop_platform
1014

11-
if RUBY_VERSION.to_f < 1.9
12-
gem "addressable", "< 2.4"
13-
end
15+
gem "addressable", "< 2.4" if ruby_version < 1.9
1416
end
1517

1618
group :development, :test do

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ run app
5252
* `:matching` is a global only option, if set to :first the first matched url will be requested (no ambigous error). Default: :all.
5353
* `:timeout` seconds to timout the requests
5454
* `:force_ssl` redirects to ssl version, if not already using it (requires `:replace_response_host`). Default: false.
55+
* `:verify_mode` the `OpenSSL::SSL` verify mode passed to Net::HTTP. Default: `OpenSSL::SSL::VERIFY_PEER`.
5556

5657
### Sample usage in a Ruby on Rails app
5758

lib/rack_reverse_proxy/middleware.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def reverse_proxy_options(options)
3232

3333
def reverse_proxy(rule, url = nil, opts = {})
3434
if rule.is_a?(String) && url.is_a?(String) && URI(url).class == URI::Generic
35-
fail Errors::GenericURI.new, url
35+
raise Errors::GenericURI.new, url
3636
end
3737
@rules << Rule.new(rule, url, opts)
3838
end
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
module RackReverseProxy
2+
# ResponseBuilder knows target response building process
3+
class ResponseBuilder
4+
def initialize(target_request, uri, options)
5+
@target_request = target_request
6+
@uri = uri
7+
@options = options
8+
end
9+
10+
def fetch
11+
setup_response
12+
target_response
13+
end
14+
15+
private
16+
17+
def setup_response
18+
set_read_timeout
19+
handle_https
20+
handle_verify_mode
21+
end
22+
23+
def set_read_timeout
24+
return unless read_timeout?
25+
target_response.read_timeout = options[:timeout]
26+
end
27+
28+
def read_timeout?
29+
options[:timeout].to_i > 0
30+
end
31+
32+
def handle_https
33+
return unless https?
34+
target_response.use_ssl = true
35+
end
36+
37+
def https?
38+
"https" == uri.scheme
39+
end
40+
41+
def handle_verify_mode
42+
return unless verify_mode?
43+
target_response.verify_mode = options[:verify_mode]
44+
end
45+
46+
def verify_mode?
47+
options.key?(:verify_mode)
48+
end
49+
50+
def target_response
51+
@_target_response ||= Rack::HttpStreamingResponse.new(
52+
target_request,
53+
uri.host,
54+
uri.port
55+
)
56+
end
57+
58+
attr_reader :target_request, :uri, :options
59+
end
60+
end

lib/rack_reverse_proxy/roundtrip.rb

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1+
require "rack_reverse_proxy/response_builder"
2+
13
module RackReverseProxy
24
# FIXME: Enable them and fix issues during refactoring
35
# rubocop:disable Metrics/ClassLength
46

57
# RoundTrip represents one request-response made by rack-reverse-proxy
68
# middleware.
79
class RoundTrip
8-
def initialize(app, env, global_options, rules)
10+
def initialize(app, env, global_options, rules, response_builder_klass = ResponseBuilder)
911
@app = app
1012
@env = env
1113
@global_options = global_options
1214
@rules = rules
15+
@response_builder_klass = response_builder_klass
1316
end
1417

1518
def call
@@ -20,7 +23,7 @@ def call
2023

2124
private
2225

23-
attr_reader :app, :env, :global_options, :rules
26+
attr_reader :app, :env, :global_options, :rules, :response_builder_klass
2427

2528
def new_relic?
2629
global_options[:newrelic_instrumentation]
@@ -89,7 +92,7 @@ def host_header
8992
def set_forwarded_host
9093
return unless options[:x_forwarded_host]
9194
target_request_headers["X-Forwarded-Host"] = source_request.host
92-
target_request_headers["X-Forwarded-Port"] = "#{source_request.port}"
95+
target_request_headers["X-Forwarded-Port"] = source_request.port.to_s
9396
end
9497

9598
def initialize_http_header
@@ -133,25 +136,11 @@ def content_type?
133136
end
134137

135138
def target_response
136-
@_target_response ||= Rack::HttpStreamingResponse.new(
139+
@_target_response ||= response_builder_klass.new(
137140
target_request,
138-
uri.host,
139-
uri.port
140-
)
141-
end
142-
143-
def set_read_timeout
144-
return unless read_timeout?
145-
target_response.read_timeout = options[:timeout]
146-
end
147-
148-
def read_timeout?
149-
options[:timeout].to_i > 0
150-
end
151-
152-
def auto_use_ssl
153-
return unless "https" == uri.scheme
154-
target_response.use_ssl = true
141+
uri,
142+
options
143+
).fetch
155144
end
156145

157146
def response_headers
@@ -180,7 +169,7 @@ def replace_location_header
180169
end
181170

182171
def response_location
183-
@_response_location ||= URI(response_headers["location"])
172+
@_response_location ||= URI(response_headers["Location"])
184173
end
185174

186175
def need_replace_location?
@@ -197,9 +186,7 @@ def setup_request
197186
set_content_type
198187
end
199188

200-
def setup_response
201-
set_read_timeout
202-
auto_use_ssl
189+
def setup_response_headers
203190
replace_location_header
204191
end
205192

@@ -212,7 +199,7 @@ def proxy
212199
return https_redirect if need_https_redirect?
213200

214201
setup_request
215-
setup_response
202+
setup_response_headers
216203

217204
rack_response
218205
end
@@ -266,7 +253,7 @@ def matches
266253

267254
def non_ambiguous_match
268255
return unless ambiguous_match?
269-
fail Errors::AmbiguousMatch.new(path, matches)
256+
raise Errors::AmbiguousMatch.new(path, matches)
270257
end
271258

272259
def ambiguous_match?

lib/rack_reverse_proxy/rule.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def build_matcher(spec)
4848
return /^#{spec}/ if spec.is_a?(String)
4949
return spec if spec.respond_to?(:match)
5050
return spec if spec.respond_to?(:call)
51-
fail ArgumentError, "Invalid Rule for reverse_proxy"
51+
raise ArgumentError, "Invalid Rule for reverse_proxy"
5252
end
5353

5454
# Candidate represents a request being matched

lib/rack_reverse_proxy/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#:nodoc:
22
module RackReverseProxy
3-
VERSION = "0.9.1"
3+
VERSION = "0.9.1".freeze
44
end

spec/rack/reverse_proxy_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ def app
460460
#:nodoc:
461461
class Matcher
462462
def self.match(path)
463-
return unless path.match(%r{^/(test|users)})
463+
return unless path =~ %r{^/(test|users)}
464464
Matcher.new
465465
end
466466

@@ -504,7 +504,7 @@ def initialize(rackreq)
504504
end
505505

506506
def self.match(path, _headers, rackreq)
507-
return nil unless path.match(%r{^/(test|users)})
507+
return nil unless path =~ %r{^/(test|users)}
508508
RequestMatcher.new(rackreq)
509509
end
510510

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
require "spec_helper"
2+
3+
module RackReverseProxy
4+
RSpec.describe ResponseBuilder do
5+
let(:options) { {} }
6+
let(:uri_opt) { { :uri => "http://example.org/hello/world" } }
7+
let(:request) { double("Request") }
8+
9+
subject(:response) do
10+
ResponseBuilder.new(
11+
request,
12+
URI(uri_opt[:uri]),
13+
options
14+
).fetch
15+
end
16+
17+
it "is a Rack::HttpStreamingResponse" do
18+
expect(response).to be_a(Rack::HttpStreamingResponse)
19+
end
20+
21+
it "sets up read timeout" do
22+
options[:timeout] = 42
23+
expect(response.read_timeout).to eq(42)
24+
end
25+
26+
it "sets up ssl when needed" do
27+
uri_opt[:uri] = "https://example.org/hello/world"
28+
expect(response.use_ssl).to eq(true)
29+
end
30+
31+
it "it is possible to change ssl verify mode" do
32+
mode = OpenSSL::SSL::VERIFY_NONE
33+
options[:verify_mode] = mode
34+
expect(response.verify_mode).to eq(mode)
35+
end
36+
end
37+
end

0 commit comments

Comments
 (0)