right_http_connection 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +25 -1
- data/lib/{net_fix.rb → base/net_fix.rb} +21 -3
- data/lib/{support.rb → base/support.rb} +0 -0
- data/lib/{version.rb → base/version.rb} +1 -1
- data/lib/right_http_connection.rb +112 -38
- data/right_http_connection.gemspec +1 -1
- data/spec/client/cacert.cer +0 -0
- data/spec/client/cacert.pem +17 -0
- data/spec/client/cert.pem +18 -0
- data/spec/client/key.pem +27 -0
- data/spec/really_dumb_webserver.rb +13 -4
- metadata +13 -11
data/History.txt
CHANGED
@@ -57,6 +57,30 @@ Initial public release
|
|
57
57
|
* fixed a bug: <NoMethodError: You have a nil object when you didn't expect it!
|
58
58
|
The error occurred while evaluating nil.body_stream>
|
59
59
|
|
60
|
-
== 1.2.5
|
60
|
+
== 1.2.5
|
61
61
|
|
62
62
|
- ActiveSupport dependency removal
|
63
|
+
|
64
|
+
|
65
|
+
== 1.3.0
|
66
|
+
- Added:
|
67
|
+
- support for using through proxies
|
68
|
+
- functional tests
|
69
|
+
|
70
|
+
== 1.3.1
|
71
|
+
- Added:
|
72
|
+
- SSL certificate handshake support
|
73
|
+
- more specs
|
74
|
+
- ability to give client side key and certificate inline
|
75
|
+
- Fixed: some minor glitches
|
76
|
+
|
77
|
+
== 1.4.0
|
78
|
+
- Added
|
79
|
+
- license
|
80
|
+
- HTTP_PROXY env variable support
|
81
|
+
- Fixed
|
82
|
+
- context-length issue (thx kristianm)
|
83
|
+
- exception handling
|
84
|
+
- connection is now closed on any exception
|
85
|
+
- connection is reestablished when credentials change
|
86
|
+
- some other minor bugs
|
@@ -91,18 +91,30 @@ module Net
|
|
91
91
|
private
|
92
92
|
|
93
93
|
def send_request_with_body(sock, ver, path, body, send_only=nil)
|
94
|
-
self.content_length = body.length
|
94
|
+
self.content_length = body.respond_to?(:bytesize) ? body.bytesize : body.length
|
95
95
|
delete 'Transfer-Encoding'
|
96
96
|
supply_default_content_type
|
97
97
|
write_header(sock, ver, path) unless send_only == :body
|
98
|
-
sock.write(body)
|
98
|
+
sock.write(body && body.to_s) unless send_only == :header
|
99
99
|
end
|
100
100
|
|
101
101
|
def send_request_with_body_stream(sock, ver, path, f, send_only=nil)
|
102
|
+
# KD: Fix 'content-length': it must not be greater than a piece of file left to be read.
|
103
|
+
# Otherwise the connection may behave like crazy causing 4xx or 5xx responses
|
104
|
+
#
|
105
|
+
# Only do this helpful thing if the stream responds to :pos (it may be something
|
106
|
+
# that responds to :read and :size but not :pos).
|
107
|
+
if f.respond_to?(:pos)
|
108
|
+
file_size = f.respond_to?(:lstat) ? f.lstat.size : f.size
|
109
|
+
bytes_to_read = [ file_size - f.pos, self.content_length.to_i ].sort.first
|
110
|
+
self.content_length = bytes_to_read
|
111
|
+
end
|
112
|
+
|
102
113
|
unless content_length() or chunked?
|
103
114
|
raise ArgumentError,
|
104
115
|
"Content-Length not given and Transfer-Encoding is not `chunked'"
|
105
116
|
end
|
117
|
+
bytes_to_read ||= content_length()
|
106
118
|
supply_default_content_type
|
107
119
|
write_header(sock, ver, path) unless send_only == :body
|
108
120
|
unless send_only == :header
|
@@ -112,8 +124,14 @@ module Net
|
|
112
124
|
end
|
113
125
|
sock.write "0\r\n\r\n"
|
114
126
|
else
|
115
|
-
|
127
|
+
# KD: When we read/write over file EOF it sometimes make the connection unstable
|
128
|
+
read_size = [ @@local_read_size, bytes_to_read ].sort.first
|
129
|
+
while s = f.read(read_size)
|
116
130
|
sock.write s
|
131
|
+
# Make sure we do not read over EOF or more than expected content-length
|
132
|
+
bytes_to_read -= read_size
|
133
|
+
break if bytes_to_read <= 0
|
134
|
+
read_size = bytes_to_read if bytes_to_read < read_size
|
117
135
|
end
|
118
136
|
end
|
119
137
|
end
|
File without changes
|
@@ -24,7 +24,7 @@
|
|
24
24
|
module RightHttpConnection #:nodoc:
|
25
25
|
module VERSION #:nodoc:
|
26
26
|
MAJOR = 1 unless defined?(MAJOR)
|
27
|
-
MINOR =
|
27
|
+
MINOR = 4 unless defined?(MINOR)
|
28
28
|
TINY = 0 unless defined?(TINY)
|
29
29
|
|
30
30
|
STRING = [MAJOR, MINOR, TINY].join('.') unless defined?(STRING)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2007-
|
2
|
+
# Copyright (c) 2007-2011 RightScale Inc
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -27,9 +27,9 @@ require "time"
|
|
27
27
|
require "logger"
|
28
28
|
|
29
29
|
$:.unshift(File.dirname(__FILE__))
|
30
|
-
require 'version'
|
31
|
-
require 'support'
|
32
|
-
require
|
30
|
+
require 'base/version'
|
31
|
+
require 'base/support'
|
32
|
+
require 'base/net_fix'
|
33
33
|
|
34
34
|
module Rightscale
|
35
35
|
|
@@ -137,26 +137,47 @@ them.
|
|
137
137
|
# :raise_on_timeout # do not perform a retry if timeout is received (false by default)
|
138
138
|
def initialize(params={})
|
139
139
|
@params = params
|
140
|
+
|
141
|
+
#set up logging first
|
142
|
+
@logger = get_param(:logger) ||
|
143
|
+
(RAILS_DEFAULT_LOGGER if defined?(RAILS_DEFAULT_LOGGER)) ||
|
144
|
+
Logger.new(STDOUT)
|
145
|
+
|
146
|
+
env_proxy_host, env_proxy_port, env_proxy_username, env_proxy_password = get_proxy_info_for_env if ENV['HTTP_PROXY']
|
147
|
+
|
140
148
|
@params[:http_connection_retry_count] ||= @@params[:http_connection_retry_count]
|
141
149
|
@params[:http_connection_open_timeout] ||= @@params[:http_connection_open_timeout]
|
142
150
|
@params[:http_connection_read_timeout] ||= @@params[:http_connection_read_timeout]
|
143
151
|
@params[:http_connection_retry_delay] ||= @@params[:http_connection_retry_delay]
|
144
|
-
@params[:proxy_host] ||= @@params[:proxy_host]
|
145
|
-
@params[:proxy_port] ||= @@params[:proxy_port]
|
146
|
-
@params[:proxy_username] ||= @@params[:proxy_username]
|
147
|
-
@params[:proxy_password] ||= @@params[:proxy_password]
|
152
|
+
@params[:proxy_host] ||= @@params[:proxy_host] || env_proxy_host
|
153
|
+
@params[:proxy_port] ||= @@params[:proxy_port] || env_proxy_port
|
154
|
+
@params[:proxy_username] ||= @@params[:proxy_username] || env_proxy_username
|
155
|
+
@params[:proxy_password] ||= @@params[:proxy_password] || env_proxy_password
|
156
|
+
|
148
157
|
@http = nil
|
149
158
|
@server = nil
|
150
|
-
@logger = get_param(:logger) ||
|
151
|
-
(RAILS_DEFAULT_LOGGER if defined?(RAILS_DEFAULT_LOGGER)) ||
|
152
|
-
Logger.new(STDOUT)
|
153
159
|
#--------------
|
154
160
|
# Retry state - Keep track of errors on a per-server basis
|
155
161
|
#--------------
|
156
162
|
@state = {} # retry state indexed by server: consecutive error count, error time, and error
|
163
|
+
|
157
164
|
@eof = {}
|
158
165
|
end
|
159
166
|
|
167
|
+
def get_proxy_info_for_env
|
168
|
+
parsed_uri = URI.parse(ENV['HTTP_PROXY'])
|
169
|
+
if parsed_uri.scheme.to_s.downcase == 'http'
|
170
|
+
return parsed_uri.host, parsed_uri.port, parsed_uri.user, parsed_uri.password
|
171
|
+
else
|
172
|
+
@logger.warn "Invalid protocol in ENV['HTTP_PROXY'] URI = #{ENV['HTTP_PROXY'].inspect} expecting 'http' got #{parsed_uri.scheme.inspect}"
|
173
|
+
return
|
174
|
+
end
|
175
|
+
rescue Exception => e
|
176
|
+
@logger.warn "Error parsing ENV['HTTP_PROXY'] with exception: #{e.message}"
|
177
|
+
return
|
178
|
+
end
|
179
|
+
private :get_proxy_info_for_env
|
180
|
+
|
160
181
|
def get_param(name, custom_options={})
|
161
182
|
custom_options [name] || @params[name] || @@params[name]
|
162
183
|
end
|
@@ -207,7 +228,9 @@ them.
|
|
207
228
|
end
|
208
229
|
|
209
230
|
# add an error for a server
|
210
|
-
def error_add(
|
231
|
+
def error_add(error)
|
232
|
+
message = error
|
233
|
+
message = "#{error.class.name}: #{error.message}" if error.is_a?(Exception)
|
211
234
|
@state[@server] = { :count => error_count+1, :time => Time.now, :message => message }
|
212
235
|
end
|
213
236
|
|
@@ -218,7 +241,7 @@ them.
|
|
218
241
|
|
219
242
|
# Error message stuff...
|
220
243
|
def banana_message
|
221
|
-
return "#{@server} temporarily unavailable: (#{error_message})"
|
244
|
+
return "#{@protocol}://#{@server}:#{@port} temporarily unavailable: (#{error_message})"
|
222
245
|
end
|
223
246
|
|
224
247
|
def err_header
|
@@ -280,6 +303,8 @@ them.
|
|
280
303
|
end
|
281
304
|
end
|
282
305
|
|
306
|
+
SECURITY_PARAMS = [:cert, :key, :cert_file, :key_file, :ca_file]
|
307
|
+
|
283
308
|
# Start a fresh connection. The object closes any existing connection and
|
284
309
|
# opens a new one.
|
285
310
|
def start(request_params)
|
@@ -293,10 +318,15 @@ them.
|
|
293
318
|
@proxy_port = request_params[:proxy_port]
|
294
319
|
@proxy_username = request_params[:proxy_username]
|
295
320
|
@proxy_password = request_params[:proxy_password]
|
321
|
+
|
322
|
+
SECURITY_PARAMS.each do |param_name|
|
323
|
+
@params[param_name] = request_params[param_name]
|
324
|
+
end
|
296
325
|
|
297
326
|
@logger.info("Opening new #{@protocol.upcase} connection to #@server:#@port")
|
327
|
+
|
298
328
|
@logger.info("Connecting to proxy #{@proxy_host}:#{@proxy_port} with username" +
|
299
|
-
" #{@proxy_username}") unless @proxy_host.nil?
|
329
|
+
" #{@proxy_username.inspect}") unless @proxy_host.nil?
|
300
330
|
|
301
331
|
@http = Net::HTTP.new(@server, @port, @proxy_host, @proxy_port, @proxy_username,
|
302
332
|
@proxy_password)
|
@@ -305,10 +335,9 @@ them.
|
|
305
335
|
|
306
336
|
if @protocol == 'https'
|
307
337
|
verifyCallbackProc = Proc.new{ |ok, x509_store_ctx|
|
338
|
+
# List of error codes: http://www.openssl.org/docs/apps/verify.html
|
308
339
|
code = x509_store_ctx.error
|
309
340
|
msg = x509_store_ctx.error_string
|
310
|
-
#debugger
|
311
|
-
@logger.warn("##### #{@server} certificate verify failed: #{msg}") unless code == 0
|
312
341
|
if request_params[:fail_if_ca_mismatch] && code != 0
|
313
342
|
false
|
314
343
|
else
|
@@ -316,14 +345,44 @@ them.
|
|
316
345
|
end
|
317
346
|
}
|
318
347
|
@http.use_ssl = true
|
348
|
+
|
319
349
|
ca_file = get_param(:ca_file)
|
320
|
-
if ca_file
|
321
|
-
|
350
|
+
if ca_file && File.exists?(ca_file)
|
351
|
+
# Documentation for 'http.rb':
|
352
|
+
# : verify_mode, verify_mode=((|mode|))
|
353
|
+
# Sets the flags for server the certification verification at
|
354
|
+
# beginning of SSL/TLS session.
|
355
|
+
# OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER is acceptable.
|
356
|
+
#
|
357
|
+
# KHRVI: looks like the constant VERIFY_FAIL_IF_NO_PEER_CERT is not acceptable
|
322
358
|
@http.verify_callback = verifyCallbackProc
|
323
|
-
@http.ca_file
|
359
|
+
@http.ca_file= ca_file
|
360
|
+
@http.verify_mode = get_param(:use_server_auth) ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
|
361
|
+
# The depth count is 'level 0:peer certificate', 'level 1: CA certificate', 'level 2: higher level CA certificate', and so on.
|
362
|
+
# Setting the maximum depth to 2 allows the levels 0, 1, and 2. The default depth limit is 9, allowing for the peer certificate and additional 9 CA certificates.
|
363
|
+
@http.verify_depth = 9
|
324
364
|
else
|
325
365
|
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
326
366
|
end
|
367
|
+
|
368
|
+
# CERT
|
369
|
+
cert_file = get_param(:cert_file, request_params)
|
370
|
+
cert = File.read(cert_file) if cert_file && File.exists?(cert_file)
|
371
|
+
cert ||= get_param(:cert, request_params)
|
372
|
+
# KEY
|
373
|
+
key_file = get_param(:key_file, request_params)
|
374
|
+
key = File.read(key_file) if key_file && File.exists?(key_file)
|
375
|
+
key ||= get_param(:key, request_params)
|
376
|
+
if cert && key
|
377
|
+
begin
|
378
|
+
@http.verify_callback = verifyCallbackProc
|
379
|
+
@http.cert = OpenSSL::X509::Certificate.new(cert)
|
380
|
+
@http.key = OpenSSL::PKey::RSA.new(key)
|
381
|
+
rescue OpenSSL::PKey::RSAError, OpenSSL::X509::CertificateError => e
|
382
|
+
@logger.error "##### Error loading SSL client cert or key: #{e.message} :: backtrace #{e.backtrace}"
|
383
|
+
raise e
|
384
|
+
end
|
385
|
+
end
|
327
386
|
end
|
328
387
|
# open connection
|
329
388
|
@http.start
|
@@ -359,14 +418,21 @@ them.
|
|
359
418
|
current_params = @params.merge(request_params)
|
360
419
|
exception = get_param(:exception, current_params) || RuntimeError
|
361
420
|
|
421
|
+
# Re-establish the connection if any of auth params has changed
|
422
|
+
same_auth_params_as_before = SECURITY_PARAMS.select do |param|
|
423
|
+
request_params[param] != get_param(param)
|
424
|
+
end.empty?
|
425
|
+
|
362
426
|
# We save the offset here so that if we need to retry, we can return the file pointer to its initial position
|
363
427
|
mypos = get_fileptr_offset(current_params)
|
364
428
|
loop do
|
429
|
+
|
365
430
|
current_params[:protocol] ||= (current_params[:port] == 443 ? 'https' : 'http')
|
366
431
|
# (re)open connection to server if none exists or params has changed
|
367
|
-
same_server_as_before = @server == current_params[:server]
|
368
|
-
@port == current_params[:port]
|
369
|
-
@protocol == current_params[:protocol]
|
432
|
+
same_server_as_before = @server == current_params[:server] &&
|
433
|
+
@port == current_params[:port] &&
|
434
|
+
@protocol == current_params[:protocol] &&
|
435
|
+
same_auth_params_as_before
|
370
436
|
|
371
437
|
# if we are inside a delay between retries: no requests this time!
|
372
438
|
# (skip this step if the endpoint has changed)
|
@@ -389,6 +455,7 @@ them.
|
|
389
455
|
unless @http &&
|
390
456
|
@http.started? &&
|
391
457
|
same_server_as_before
|
458
|
+
same_auth_params_as_before = true
|
392
459
|
start(current_params)
|
393
460
|
end
|
394
461
|
|
@@ -414,8 +481,9 @@ them.
|
|
414
481
|
|
415
482
|
# EOFError means the server closed the connection on us.
|
416
483
|
rescue EOFError => e
|
484
|
+
finish(e.message)
|
485
|
+
|
417
486
|
@logger.debug("#{err_header} server #{@server} closed connection")
|
418
|
-
@http = nil
|
419
487
|
|
420
488
|
# if we have waited long enough - raise an exception...
|
421
489
|
if raise_on_eof_exception?
|
@@ -427,31 +495,35 @@ them.
|
|
427
495
|
# We will be retrying the request, so reset the file pointer
|
428
496
|
reset_fileptr_offset(request, mypos)
|
429
497
|
end
|
430
|
-
rescue
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
498
|
+
rescue ArgumentError => e
|
499
|
+
finish(e.message)
|
500
|
+
|
501
|
+
if e.message.include?('wrong number of arguments (5 for 4)')
|
502
|
+
# seems our net_fix patch was overriden...
|
503
|
+
raise exception.new('incompatible Net::HTTP monkey-patch')
|
504
|
+
else
|
505
|
+
raise e
|
506
|
+
end
|
507
|
+
|
508
|
+
rescue Timeout::Error, SocketError, SystemCallError, Interrupt => e # See comment at bottom for the list of errors seen...
|
509
|
+
finish(e.message)
|
510
|
+
if e.is_a?(Errno::ETIMEDOUT) || e.is_a?(Timeout::Error)
|
511
|
+
# Omit retries if it was explicitly requested
|
435
512
|
# #6481:
|
436
513
|
# ... When creating a resource in EC2 (instance, volume, snapshot, etc) it is undetermined what happened if the call times out.
|
437
514
|
# The resource may or may not have been created in EC2. Retrying the call may cause multiple resources to be created...
|
438
|
-
raise e
|
439
|
-
|
440
|
-
|
441
|
-
if e.is_a?(Interrupt) && !timeout_exception
|
515
|
+
raise exception.new("#{e.class.name}: #{e.message}") if current_params[:raise_on_timeout]
|
516
|
+
elsif e.is_a?(Interrupt)
|
517
|
+
# if ctrl+c is pressed - we have to reraise exception to terminate proggy
|
442
518
|
@logger.debug( "#{err_header} request to server #{@server} interrupted by ctrl-c")
|
443
|
-
raise
|
444
|
-
elsif e.is_a?(ArgumentError) && e.message.include?('wrong number of arguments (5 for 4)')
|
445
|
-
# seems our net_fix patch was overriden...
|
446
|
-
raise exception.new('incompatible Net::HTTP monkey-patch')
|
519
|
+
raise e
|
447
520
|
end
|
448
521
|
# oops - we got a banana: log it
|
449
|
-
error_add(e
|
522
|
+
error_add(e)
|
450
523
|
@logger.warn("#{err_header} request failure count: #{error_count}, exception: #{e.inspect}")
|
451
524
|
|
452
525
|
# We will be retrying the request, so reset the file pointer
|
453
526
|
reset_fileptr_offset(request, mypos)
|
454
|
-
|
455
527
|
end
|
456
528
|
end
|
457
529
|
end
|
@@ -462,6 +534,8 @@ them.
|
|
462
534
|
@logger.info("Closing #{@http.use_ssl? ? 'HTTPS' : 'HTTP'} connection to #{@http.address}:#{@http.port}#{reason}")
|
463
535
|
@http.finish
|
464
536
|
end
|
537
|
+
ensure
|
538
|
+
@http = nil
|
465
539
|
end
|
466
540
|
|
467
541
|
# Errors received during testing:
|
@@ -22,7 +22,7 @@
|
|
22
22
|
#++
|
23
23
|
|
24
24
|
require 'rubygems'
|
25
|
-
require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'version'))
|
25
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'base', 'version'))
|
26
26
|
|
27
27
|
Gem::Specification.new do |spec|
|
28
28
|
spec.name = 'right_http_connection'
|
Binary file
|
@@ -0,0 +1,17 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIICxjCCAa6gAwIBAgIJAJYV+DprCQ1CMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
|
3
|
+
BAMTCE15VGVzdENBMB4XDTExMDkxMzIyNTMxMVoXDTEyMDkxMjIyNTMxMVowEzER
|
4
|
+
MA8GA1UEAxMITXlUZXN0Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
5
|
+
AQCwmvBNrd7t/Z7ZVo1YfimpGgerOn1vXZY+OGJtqo+pN11Ei7dhVQfWBd2dAkYH
|
6
|
+
B8NlPr5QyxmIT88JIRKEzk7ZZ+nRdfyoocg63FeLn+b6OeR5hwyK38aMRbhqY1Gq
|
7
|
+
aIKMYyEpv0YNbuwoomv5Atl8mwvuUFr2XKndyzsrP1TrTCHH4lA5P0UUzIjVyyz9
|
8
|
+
F4YAjGLjjoVO5R02LmZ/h/LqT6bJQ+cu/2JeIWGVnjKoFvyWHd0TOaOGDHlQc5h8
|
9
|
+
RxgdOFrjsZGpQ5sKlhcI+9p0LOXqVfoC2J2ZWtAjFo0d54E/OarnBPFB6VNtoSmj
|
10
|
+
l0z+OLGMKuDGaLflXNE0STVdAgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0P
|
11
|
+
BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAAbVkvPzS59uhX6Ox1ZT92cJXW8yjP
|
12
|
+
IyXrZjcWlaKQSKcn8v5RpebtVA+pL6mCActBE8fMac5ixlwTTnF5LHb9v80XuXMe
|
13
|
+
MXooQZBliyim5lVCp9gjKZYXEeVDphsuwDr5M4qO7tdZTB1ezCULObVF1N7qMwpO
|
14
|
+
yWI6zifRtLsgWmnRyaeVyv2uNRYoAEsAd2Dj4oJjvuyc9U5QUhtsXwD3jvSPsdi6
|
15
|
+
Mbr5tVIcZSpT4W9PSiZw2ZUZXIEbxX+w+FsuehhvoFJCi05R1ashCPxQA13bOJK0
|
16
|
+
BmbHqeLDzJCK0+kQs8CRIGWGTGng84AyJ5MygGzd0WN9jtZslWTPDtbz
|
17
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,18 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIC9TCCAd2gAwIBAgIBAjANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl
|
3
|
+
c3RDQTAeFw0xMTA5MTMyMzAxMDVaFw0xMjA5MTIyMzAxMDVaMDgxJTAjBgNVBAMM
|
4
|
+
HE1haGVuZHJhLUt1dGFyZXMtTWFjQm9vay1Qcm8xDzANBgNVBAoMBmNsaWVudDCC
|
5
|
+
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcEhrVTKKgWVqTUBCGBWJlD
|
6
|
+
u7RIk7kPcGAARy7Ctx+4VReEYlgVRqECzt4itglNdrQkUVCHXE0rwJMOozE8Hsgh
|
7
|
+
rAOQvxzPJhG3hPUJf/VkfB+Dn0xRsPvrE90HpRlSqdT8X6iuryPEmp5RyMaY122P
|
8
|
+
r/+Xs+lHhRlKQPdRpYXHlOwWX/U56Wy7jjGU9lONBEIEV8tD5ExzkCG23nbCvrFr
|
9
|
+
/2c4VjrAwXR2RyYfSDRyc/obky49ydKZ8/HKbS3VdJYAWBI4Wnj2hayCcZggEFB0
|
10
|
+
zg/IDXpOjnr6zV5UEfdaMIH4/K44ISX7xmZWGmQ3464NTmykj5xUMmfy3rVNREsC
|
11
|
+
AwEAAaMvMC0wCQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwEwYDVR0lBAwwCgYIKwYB
|
12
|
+
BQUHAwIwDQYJKoZIhvcNAQEFBQADggEBACmNyOoCvNsz8N3LN47VZK7aev54tjtd
|
13
|
+
zJilLgAxEGBeaIvHX9LDkgi3sQAvHMHc3VIq4BoEd9TNtyxIrUdc2EG1TCJvHINP
|
14
|
+
7YoHtbajvT3bhVLlnWjB7jHp9jNfZtHL7aEDp+5eqPT6wzaVeiu1nABs7gudCQq1
|
15
|
+
CJw0Mfz1U3mG0sTb5JlRt7toce9dW0R6jfYTmTj6Yzu3kcgYjQKy2k2BCInLOIhz
|
16
|
+
6tyOH51mCGAy1zgcWMvuyKYCeJQxRd46GrR2peyE2wYY6SfSlrK16pjaz48S3uhI
|
17
|
+
01jd+HA1LARcImMhkMa/QFTo4uI7lx9Q+Y06Ny+rMuTNSnBSIgCUPQk=
|
18
|
+
-----END CERTIFICATE-----
|
data/spec/client/key.pem
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIIEpAIBAAKCAQEAxwSGtVMoqBZWpNQEIYFYmUO7tEiTuQ9wYABHLsK3H7hVF4Ri
|
3
|
+
WBVGoQLO3iK2CU12tCRRUIdcTSvAkw6jMTweyCGsA5C/HM8mEbeE9Ql/9WR8H4Of
|
4
|
+
TFGw++sT3QelGVKp1PxfqK6vI8SanlHIxpjXbY+v/5ez6UeFGUpA91GlhceU7BZf
|
5
|
+
9TnpbLuOMZT2U40EQgRXy0PkTHOQIbbedsK+sWv/ZzhWOsDBdHZHJh9INHJz+huT
|
6
|
+
Lj3J0pnz8cptLdV0lgBYEjhaePaFrIJxmCAQUHTOD8gNek6OevrNXlQR91owgfj8
|
7
|
+
rjghJfvGZlYaZDfjrg1ObKSPnFQyZ/LetU1ESwIDAQABAoIBAB23pU3KHxYKT+HI
|
8
|
+
7tz57XrlTE/9TmGh1ovfPsHSvXl1Eu+yCuVQN/2u56jv0fLNqF351lKKA9RaJiVP
|
9
|
+
WDrv2UDVFlRp9r+chvi6SJY2Vu8TlB04kD7bK+xSC+NDUvnXCBkPnlEX1HsozlW5
|
10
|
+
rJtLE0/+1q75vhmlXlCKb+z+OhMhmFnaWTf/xLNbkItO5tOf+mv/CoqBUSEk+i9t
|
11
|
+
O6Zjzh02jbpW7xH3jJ/UexKMYOuqxoOMfC/MI6q3Qcu2OeZgl8cEIi94sjafq9ob
|
12
|
+
WcFTrZY+YG5b1SE8ILg69Fkqve5d2Mn1sN8mYZxLeM0C/ATNghM5uSWhdze06bNu
|
13
|
+
fpcgvOECgYEA/L+J/xVgUySUByELEBosY8q0HYG5Msq+GT7L5GMIoEmEp4j6MPRu
|
14
|
+
kF/DihxefcvDyVRLhJh7o/kwR7Vwe4wP9145e3MOe9b7IH6pEwV0nAsBO6ldVToX
|
15
|
+
gvrHOIoySNt/XtRurrbtZ08OtUDCLIRQATTnY9ieh8sxTyl1G9GehoMCgYEAyZQE
|
16
|
+
r4ByBzXjTiuaODH6tPndbKFxRo2iis9CyxqYXAMDkjvF4NEpQyW5ucRxpRqTt51P
|
17
|
+
kR13jdadnOF4t82M0qqEH3G6H4biKisY1jXRNH7mPSbyPbC4vxrQhnAEF3RiqbXz
|
18
|
+
f2LUC4uOtLzW7HeyjEiZy2mg7UKdOfsmmJ//oJkCgYEAxZF/8GqoQjW8lJoKyMp8
|
19
|
+
2oDQLKSDvSVoVdmVjfCwBIOTc1aKpAveBXMmKealIlZOtCj1Yy/CrlmSmOtGgvzo
|
20
|
+
WihIbKxyrPFOmocH6PuBvJyJmTZ5464mRNd9NUApsHQL63fJET+i8feFer+lSSEg
|
21
|
+
XOEa4xyoR2PZJpU0mstPzLsCgYBvcS3F+TURV3F7Xg+80aTROPJ5hCej4dni9ALx
|
22
|
+
Vpq1A9WNmw4i5H/zZ3/ue/R4WuEfuhCrIade+y/X869RrooUTcENwUos891Fgt4Q
|
23
|
+
T2CBrUaMuGNkR7dbr+9o47TfYrDJMpaT7odceqNCuMP5p5NGizy7gII/qXxS+c60
|
24
|
+
woAIwQKBgQCiIfXZtAgYTPL23CQrxIMFwnlO0TiOe0ha0et7hjCh/CStG7NET7KK
|
25
|
+
U1L1kfyl1YDgoJbLXTsG2WwGZRnK1oyEEFj2iY5EvwoMPr0Sv8/CiOIyEfC62s3V
|
26
|
+
MoHemunnFhAj+JAy2HTKV0VYiNNNAxz3CBG8yMLK7YAMgPw1/HQQLQ==
|
27
|
+
-----END RSA PRIVATE KEY-----
|
@@ -23,7 +23,7 @@
|
|
23
23
|
|
24
24
|
require 'webrick'
|
25
25
|
|
26
|
-
ssl_cert, ssl_key = ARGV[0], ARGV[1]
|
26
|
+
ssl_cert, ssl_key, ca_cert = ARGV[0], ARGV[1], ARGV[2]
|
27
27
|
|
28
28
|
# Monkey patch bad User-Agent parsing
|
29
29
|
module WEBrick::AccessLog
|
@@ -52,7 +52,7 @@ module WEBrick::AccessLog
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
logger = WEBrick::Log.new($stderr, WEBrick::Log::WARN)
|
55
|
+
logger = WEBrick::Log.new($stderr, WEBrick::Log::WARN)#WEBrick::Log::DEBUG
|
56
56
|
config = {}
|
57
57
|
config[:Port] = 7890
|
58
58
|
config[:Logger] = logger
|
@@ -60,10 +60,19 @@ config[:AccessLog] = [[$stdout, WEBrick::AccessLog::COMBINED_LOG_FORMAT]]
|
|
60
60
|
unless ssl_cert.nil? || ssl_key.nil?
|
61
61
|
require 'webrick/https'
|
62
62
|
config[:SSLEnable] = true
|
63
|
-
|
63
|
+
# http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html#
|
64
|
+
# SSL_VERIFY_FAIL_IF_NO_PEER_CERT
|
65
|
+
# => Server mode: if the client did not return a certificate, the TLS/SSL handshake is immediately terminated with a 'handshake failure' alert.
|
66
|
+
# => This flag must be used together with SSL_VERIFY_PEER.
|
67
|
+
config[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_PEER
|
68
|
+
config[:SSLVerifyClient] |= OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT if ca_cert
|
64
69
|
config[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(File.open(ssl_key).read)
|
65
70
|
config[:SSLCertificate] = OpenSSL::X509::Certificate.new(File.open(ssl_cert).read)
|
66
|
-
config[:SSLCertName]
|
71
|
+
# KHRVI: option config[:SSLCertName] does make sense only when config[:SSLCertificate] isn't specified
|
72
|
+
# see: webrick/ssl.rb method :setup_ssl_context
|
73
|
+
# config[:SSLCertName] = [["CN", "Graham Hughes"]]
|
74
|
+
config[:SSLVerifyDepth] = 9
|
75
|
+
config[:SSLCACertificateFile] = ca_cert if ca_cert
|
67
76
|
end
|
68
77
|
$stdout.sync = true
|
69
78
|
server = WEBrick::HTTPServer.new(config)
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: right_http_connection
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 7
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
8
|
+
- 4
|
9
9
|
- 0
|
10
|
-
version: 1.
|
10
|
+
version: 1.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- RightScale, Inc.
|
@@ -15,8 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
19
|
-
default_executable:
|
18
|
+
date: 2013-06-13 00:00:00 Z
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
22
21
|
name: rake
|
@@ -115,10 +114,10 @@ files:
|
|
115
114
|
- Manifest.txt
|
116
115
|
- README.txt
|
117
116
|
- Rakefile
|
118
|
-
- lib/net_fix.rb
|
117
|
+
- lib/base/net_fix.rb
|
118
|
+
- lib/base/support.rb
|
119
|
+
- lib/base/version.rb
|
119
120
|
- lib/right_http_connection.rb
|
120
|
-
- lib/support.rb
|
121
|
-
- lib/version.rb
|
122
121
|
- right_http_connection.gemspec
|
123
122
|
- spec/bad.ca
|
124
123
|
- spec/ca/Rakefile
|
@@ -128,12 +127,15 @@ files:
|
|
128
127
|
- spec/ca/demoCA/serial
|
129
128
|
- spec/ca/passphrase.txt
|
130
129
|
- spec/ca/server.csr
|
130
|
+
- spec/client/cacert.cer
|
131
|
+
- spec/client/cacert.pem
|
132
|
+
- spec/client/cert.pem
|
133
|
+
- spec/client/key.pem
|
131
134
|
- spec/good.ca
|
132
135
|
- spec/proxy_server.rb
|
133
136
|
- spec/really_dumb_webserver.rb
|
134
137
|
- spec/server.crt
|
135
138
|
- spec/server.key
|
136
|
-
has_rdoc: true
|
137
139
|
homepage: http://rightscale.rubyforge.org/
|
138
140
|
licenses: []
|
139
141
|
|
@@ -173,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
173
175
|
requirements: []
|
174
176
|
|
175
177
|
rubyforge_project: rightscale
|
176
|
-
rubygems_version: 1.
|
178
|
+
rubygems_version: 1.8.5
|
177
179
|
signing_key:
|
178
180
|
specification_version: 3
|
179
181
|
summary: RightScale's robust HTTP/S connection module
|