right_http_connection 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 (not released yet)
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) unless send_only == :header
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
- while s = f.read(@@local_read_size)
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 = 3 unless defined?(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-2008 RightScale Inc
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 "net_fix"
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(message)
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
- @http.verify_mode = OpenSSL::SSL::VERIFY_PEER
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 = 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 Exception => e # See comment at bottom for the list of errors seen...
431
- @http = nil
432
- timeout_exception = e.is_a?(Errno::ETIMEDOUT) || e.is_a?(Timeout::Error)
433
- # Omit retries if it was explicitly requested
434
- if current_params[:raise_on_timeout] && timeout_exception
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
- end
440
- # if ctrl+c is pressed - we have to reraise exception to terminate proggy
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.message)
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-----
@@ -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
- config[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_NONE
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] = [["CN", "Graham Hughes"]]
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: 27
5
- prerelease: false
4
+ hash: 7
5
+ prerelease:
6
6
  segments:
7
7
  - 1
8
- - 3
8
+ - 4
9
9
  - 0
10
- version: 1.3.0
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: 2011-03-25 00:00:00 -07:00
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.3.7
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