httpclient 2.6.0.1 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/bin/httpclient +5 -1
- data/lib/http-access2.rb +1 -1
- data/lib/httpclient.rb +37 -5
- data/lib/httpclient/auth.rb +3 -3
- data/lib/httpclient/cacert.pem +3952 -0
- data/lib/httpclient/{cacert.p7s → cacert1024.pem} +0 -0
- data/lib/httpclient/connection.rb +1 -1
- data/lib/httpclient/cookie.rb +12 -4
- data/lib/httpclient/http.rb +1 -1
- data/lib/httpclient/jruby_ssl_socket.rb +526 -0
- data/lib/httpclient/session.rb +161 -244
- data/lib/httpclient/ssl_config.rb +54 -17
- data/lib/httpclient/ssl_socket.rb +149 -0
- data/lib/httpclient/timeout.rb +1 -1
- data/lib/httpclient/util.rb +23 -1
- data/lib/httpclient/version.rb +1 -1
- data/lib/oauthclient.rb +1 -1
- data/test/{ca-chain.cert → ca-chain.pem} +0 -0
- data/test/helper.rb +7 -5
- data/test/test_auth.rb +27 -8
- data/test/test_cookie.rb +2 -2
- data/test/test_httpclient.rb +57 -21
- data/test/test_ssl.rb +70 -21
- data/test/test_webagent-cookie.rb +2 -2
- metadata +13 -10
@@ -1,5 +1,5 @@
|
|
1
1
|
# HTTPClient - HTTP client library.
|
2
|
-
# Copyright (C) 2000-
|
2
|
+
# Copyright (C) 2000-2015 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
|
3
3
|
#
|
4
4
|
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
|
5
5
|
# redistribute it and/or modify it under the same terms of Ruby's license;
|
@@ -20,20 +20,19 @@ class HTTPClient
|
|
20
20
|
#
|
21
21
|
# == Trust Anchor Control
|
22
22
|
#
|
23
|
-
# SSLConfig loads 'httpclient/cacert.
|
23
|
+
# SSLConfig loads 'httpclient/cacert.pem' as a trust anchor
|
24
24
|
# (trusted certificate(s)) with add_trust_ca in initialization time.
|
25
25
|
# This means that HTTPClient instance trusts some CA certificates by default,
|
26
|
-
# like Web browsers. 'httpclient/cacert.
|
27
|
-
# included in released package.
|
28
|
-
#
|
29
|
-
# 'cacert.p7s' is automatically generated from JDK 1.6. Regardless its
|
30
|
-
# filename extension (p7s), HTTPClient doesn't verify the signature in it.
|
26
|
+
# like Web browsers. 'httpclient/cacert.pem' is downloaded from curl web
|
27
|
+
# site by the author and included in released package.
|
31
28
|
#
|
32
29
|
# You may want to change trust anchor by yourself. Call clear_cert_store
|
33
30
|
# then add_trust_ca for that purpose.
|
34
31
|
class SSLConfig
|
35
32
|
include OpenSSL if SSLEnabled
|
36
33
|
|
34
|
+
CIPHERS_DEFAULT = "ALL:!aNULL:!eNULL:!SSLv2" # OpenSSL >1.0.0 default
|
35
|
+
|
37
36
|
# Which TLS protocol version (also called method) will be used. Defaults
|
38
37
|
# to :auto which means that OpenSSL decides (In my tests this resulted
|
39
38
|
# with always the highest available protocol being used).
|
@@ -42,18 +41,20 @@ class HTTPClient
|
|
42
41
|
# See {OpenSSL::SSL::SSLContext::METHODS} for a list of available versions
|
43
42
|
# in your specific Ruby environment.
|
44
43
|
attr_reader :ssl_version
|
45
|
-
# OpenSSL::X509::Certificate:: certificate for SSL client
|
46
|
-
# nil by default. (no client
|
44
|
+
# OpenSSL::X509::Certificate:: certificate for SSL client authentication.
|
45
|
+
# nil by default. (no client authentication)
|
47
46
|
attr_reader :client_cert
|
48
47
|
# OpenSSL::PKey::PKey:: private key for SSL client authentication.
|
49
|
-
# nil by default. (no client
|
48
|
+
# nil by default. (no client authentication)
|
50
49
|
attr_reader :client_key
|
50
|
+
attr_reader :client_key_pass
|
51
51
|
|
52
52
|
# A number which represents OpenSSL's verify mode. Default value is
|
53
53
|
# OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT.
|
54
54
|
attr_reader :verify_mode
|
55
55
|
# A number of verify depth. Certification path which length is longer than
|
56
56
|
# this depth is not allowed.
|
57
|
+
# CAUTION: this is OpenSSL specific option and ignored on JRuby.
|
57
58
|
attr_reader :verify_depth
|
58
59
|
# A callback handler for custom certificate verification. nil by default.
|
59
60
|
# If the handler is set, handler.call is invoked just after general
|
@@ -65,6 +66,8 @@ class HTTPClient
|
|
65
66
|
attr_reader :timeout
|
66
67
|
# A number of OpenSSL's SSL options. Default value is
|
67
68
|
# OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv2
|
69
|
+
# CAUTION: this is OpenSSL specific option and ignored on JRuby.
|
70
|
+
# Use ssl_version to specify the TLS version you want to use.
|
68
71
|
attr_reader :options
|
69
72
|
# A String of OpenSSL's cipher configuration. Default value is
|
70
73
|
# ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH
|
@@ -78,11 +81,17 @@ class HTTPClient
|
|
78
81
|
# For server side configuration. Ignore this.
|
79
82
|
attr_reader :client_ca # :nodoc:
|
80
83
|
|
84
|
+
# These array keeps original files/dirs that was added to @cert_store
|
85
|
+
attr_reader :cert_store_items
|
86
|
+
attr_reader :cert_store_crl_items
|
87
|
+
|
81
88
|
# Creates a SSLConfig.
|
82
89
|
def initialize(client)
|
83
90
|
return unless SSLEnabled
|
84
91
|
@client = client
|
85
92
|
@cert_store = X509::Store.new
|
93
|
+
@cert_store_items = [:default]
|
94
|
+
@cert_store_crl_items = []
|
86
95
|
@client_cert = @client_key = @client_ca = nil
|
87
96
|
@verify_mode = SSL::VERIFY_PEER | SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
88
97
|
@verify_depth = nil
|
@@ -97,7 +106,7 @@ class HTTPClient
|
|
97
106
|
@options |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2)
|
98
107
|
@options |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3)
|
99
108
|
# OpenSSL 0.9.8 default: "ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH"
|
100
|
-
@ciphers =
|
109
|
+
@ciphers = CIPHERS_DEFAULT
|
101
110
|
@cacerts_loaded = false
|
102
111
|
end
|
103
112
|
|
@@ -135,8 +144,7 @@ class HTTPClient
|
|
135
144
|
#
|
136
145
|
# Calling this method resets all existing sessions.
|
137
146
|
def set_client_cert_file(cert_file, key_file, pass = nil)
|
138
|
-
@client_cert =
|
139
|
-
@client_key = PKey::RSA.new(File.open(key_file) { |f| f.read }, pass)
|
147
|
+
@client_cert, @client_key, @client_key_pass = cert_file, key_file, pass
|
140
148
|
change_notify
|
141
149
|
end
|
142
150
|
|
@@ -155,6 +163,7 @@ class HTTPClient
|
|
155
163
|
@cacerts_loaded = true # avoid lazy override
|
156
164
|
@cert_store = X509::Store.new
|
157
165
|
@cert_store.set_default_paths
|
166
|
+
@cert_store_items = [ENV['SSL_CERT_FILE'] || :default]
|
158
167
|
change_notify
|
159
168
|
end
|
160
169
|
|
@@ -165,6 +174,7 @@ class HTTPClient
|
|
165
174
|
def clear_cert_store
|
166
175
|
@cacerts_loaded = true # avoid lazy override
|
167
176
|
@cert_store = X509::Store.new
|
177
|
+
@cert_store_items.clear
|
168
178
|
change_notify
|
169
179
|
end
|
170
180
|
|
@@ -175,6 +185,7 @@ class HTTPClient
|
|
175
185
|
def cert_store=(cert_store)
|
176
186
|
@cacerts_loaded = true # avoid lazy override
|
177
187
|
@cert_store = cert_store
|
188
|
+
@cert_store_items.clear
|
178
189
|
change_notify
|
179
190
|
end
|
180
191
|
|
@@ -188,6 +199,7 @@ class HTTPClient
|
|
188
199
|
def add_trust_ca(trust_ca_file_or_hashed_dir)
|
189
200
|
@cacerts_loaded = true # avoid lazy override
|
190
201
|
add_trust_ca_to_store(@cert_store, trust_ca_file_or_hashed_dir)
|
202
|
+
@cert_store_items << trust_ca_file_or_hashed_dir
|
191
203
|
change_notify
|
192
204
|
end
|
193
205
|
alias set_trust_ca add_trust_ca
|
@@ -211,12 +223,20 @@ class HTTPClient
|
|
211
223
|
# crl:: a OpenSSL::X509::CRL or a filename of a PEM/DER formatted
|
212
224
|
# OpenSSL::X509::CRL.
|
213
225
|
#
|
226
|
+
# On JRuby, instead of setting CRL by yourself you can set following
|
227
|
+
# options to let HTTPClient to perform revocation check with CRL and OCSP:
|
228
|
+
# -J-Dcom.sun.security.enableCRLDP=true -J-Dcom.sun.net.ssl.checkRevocation=true
|
229
|
+
# ex. jruby -J-Dcom.sun.security.enableCRLDP=true -J-Dcom.sun.net.ssl.checkRevocation=true app.rb
|
230
|
+
#
|
231
|
+
# Revoked cert example: https://test-sspev.verisign.com:2443/test-SSPEV-revoked-verisign.html
|
232
|
+
#
|
214
233
|
# Calling this method resets all existing sessions.
|
215
234
|
def add_crl(crl)
|
216
235
|
unless crl.is_a?(X509::CRL)
|
217
236
|
crl = X509::CRL.new(File.open(crl) { |f| f.read })
|
218
237
|
end
|
219
238
|
@cert_store.add_crl(crl)
|
239
|
+
@cert_store_crl_items << crl
|
220
240
|
@cert_store.flags = X509::V_FLAG_CRL_CHECK | X509::V_FLAG_CRL_CHECK_ALL
|
221
241
|
change_notify
|
222
242
|
end
|
@@ -278,7 +298,7 @@ class HTTPClient
|
|
278
298
|
change_notify
|
279
299
|
end
|
280
300
|
|
281
|
-
# interfaces for
|
301
|
+
# interfaces for SSLSocket.
|
282
302
|
def set_context(ctx) # :nodoc:
|
283
303
|
load_trust_ca unless @cacerts_loaded
|
284
304
|
@cacerts_loaded = true
|
@@ -288,8 +308,14 @@ class HTTPClient
|
|
288
308
|
ctx.verify_depth = @verify_depth if @verify_depth
|
289
309
|
ctx.verify_callback = @verify_callback || method(:default_verify_callback)
|
290
310
|
# SSL config
|
291
|
-
|
292
|
-
|
311
|
+
if @client_cert
|
312
|
+
ctx.cert = @client_cert.is_a?(X509::Certificate) ? @client_cert :
|
313
|
+
X509::Certificate.new(File.open(@client_cert) { |f| f.read })
|
314
|
+
end
|
315
|
+
if @client_key
|
316
|
+
ctx.key = @client_key.is_a?(PKey::PKey) ? @client_key :
|
317
|
+
PKey::RSA.new(File.open(@client_key) { |f| f.read }, @client_key_pass)
|
318
|
+
end
|
293
319
|
ctx.client_ca = @client_ca
|
294
320
|
ctx.timeout = @timeout
|
295
321
|
ctx.options = @options
|
@@ -405,9 +431,20 @@ class HTTPClient
|
|
405
431
|
nil
|
406
432
|
end
|
407
433
|
|
434
|
+
# Use 2014 bit certs trust anchor if possible.
|
435
|
+
# CVE-2015-1793 requires: OpenSSL >= 1.0.2d or OpenSSL >= 1.0.1p
|
436
|
+
# OpenSSL before 1.0.1 does not have CVE-2015-1793 problem
|
408
437
|
def load_cacerts(cert_store)
|
409
|
-
|
438
|
+
ver = OpenSSL::OPENSSL_VERSION
|
439
|
+
if (ver.start_with?('OpenSSL 1.0.1') && ver >= 'OpenSSL 1.0.1p') ||
|
440
|
+
(ver.start_with?('OpenSSL ') && ver >= 'OpenSSL 1.0.2d')
|
441
|
+
filename = 'cacert.pem'
|
442
|
+
else
|
443
|
+
filename = 'cacert1024.pem'
|
444
|
+
end
|
445
|
+
file = File.join(File.dirname(__FILE__), filename)
|
410
446
|
add_trust_ca_to_store(cert_store, file)
|
447
|
+
@cert_store_items << file
|
411
448
|
end
|
412
449
|
end
|
413
450
|
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# HTTPClient - HTTP client library.
|
2
|
+
# Copyright (C) 2000-2015 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
|
3
|
+
#
|
4
|
+
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
|
5
|
+
# redistribute it and/or modify it under the same terms of Ruby's license;
|
6
|
+
# either the dual license version in 2003, or any later version.
|
7
|
+
|
8
|
+
|
9
|
+
require 'httpclient/ssl_config'
|
10
|
+
|
11
|
+
|
12
|
+
class HTTPClient
|
13
|
+
|
14
|
+
# Wraps up OpenSSL::SSL::SSLSocket and offers debugging features.
|
15
|
+
class SSLSocket
|
16
|
+
def self.create_socket(session)
|
17
|
+
site = session.proxy || session.dest
|
18
|
+
socket = session.create_socket(site.host, site.port)
|
19
|
+
begin
|
20
|
+
if session.proxy
|
21
|
+
session.connect_ssl_proxy(socket, Util.urify(session.dest.to_s))
|
22
|
+
end
|
23
|
+
ssl_socket = new(socket, session.ssl_config, session.debug_dev)
|
24
|
+
ssl_socket.ssl_connect(session.dest.host)
|
25
|
+
ssl_socket
|
26
|
+
rescue
|
27
|
+
socket.close
|
28
|
+
raise
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(socket, context, debug_dev = nil)
|
33
|
+
unless SSLEnabled
|
34
|
+
raise ConfigurationError.new('Ruby/OpenSSL module is required')
|
35
|
+
end
|
36
|
+
@socket = socket
|
37
|
+
@context = context
|
38
|
+
@ssl_socket = create_openssl_socket(@socket)
|
39
|
+
@debug_dev = debug_dev
|
40
|
+
end
|
41
|
+
|
42
|
+
def ssl_connect(hostname = nil)
|
43
|
+
if hostname && @ssl_socket.respond_to?(:hostname=)
|
44
|
+
@ssl_socket.hostname = hostname
|
45
|
+
end
|
46
|
+
@ssl_socket.connect
|
47
|
+
if $DEBUG
|
48
|
+
if @ssl_socket.respond_to?(:ssl_version)
|
49
|
+
warn("Protocol version: #{@ssl_socket.ssl_version}")
|
50
|
+
end
|
51
|
+
warn("Cipher: #{@ssl_socket.cipher.inspect}")
|
52
|
+
warn("State: #{@ssl_socket.state}")
|
53
|
+
end
|
54
|
+
post_connection_check(hostname)
|
55
|
+
end
|
56
|
+
|
57
|
+
def peer_cert
|
58
|
+
@ssl_socket.peer_cert
|
59
|
+
end
|
60
|
+
|
61
|
+
def close
|
62
|
+
@ssl_socket.close
|
63
|
+
@socket.close
|
64
|
+
end
|
65
|
+
|
66
|
+
def closed?
|
67
|
+
@socket.closed?
|
68
|
+
end
|
69
|
+
|
70
|
+
def eof?
|
71
|
+
@ssl_socket.eof?
|
72
|
+
end
|
73
|
+
|
74
|
+
def gets(rs)
|
75
|
+
str = @ssl_socket.gets(rs)
|
76
|
+
debug(str)
|
77
|
+
str
|
78
|
+
end
|
79
|
+
|
80
|
+
def read(size, buf = nil)
|
81
|
+
str = @ssl_socket.read(size, buf)
|
82
|
+
debug(str)
|
83
|
+
str
|
84
|
+
end
|
85
|
+
|
86
|
+
def readpartial(size, buf = nil)
|
87
|
+
str = @ssl_socket.readpartial(size, buf)
|
88
|
+
debug(str)
|
89
|
+
str
|
90
|
+
end
|
91
|
+
|
92
|
+
def <<(str)
|
93
|
+
rv = @ssl_socket.write(str)
|
94
|
+
debug(str)
|
95
|
+
rv
|
96
|
+
end
|
97
|
+
|
98
|
+
def flush
|
99
|
+
@ssl_socket.flush
|
100
|
+
end
|
101
|
+
|
102
|
+
def sync
|
103
|
+
@ssl_socket.sync
|
104
|
+
end
|
105
|
+
|
106
|
+
def sync=(sync)
|
107
|
+
@ssl_socket.sync = sync
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def post_connection_check(hostname)
|
113
|
+
verify_mode = @context.verify_mode || OpenSSL::SSL::VERIFY_NONE
|
114
|
+
if verify_mode == OpenSSL::SSL::VERIFY_NONE
|
115
|
+
return
|
116
|
+
elsif @ssl_socket.peer_cert.nil? and
|
117
|
+
check_mask(verify_mode, OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT)
|
118
|
+
raise OpenSSL::SSL::SSLError.new('no peer cert')
|
119
|
+
end
|
120
|
+
if @ssl_socket.respond_to?(:post_connection_check) and RUBY_VERSION > "1.8.4"
|
121
|
+
@ssl_socket.post_connection_check(hostname)
|
122
|
+
else
|
123
|
+
@context.post_connection_check(@ssl_socket.peer_cert, hostname)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def check_mask(value, mask)
|
128
|
+
value & mask == mask
|
129
|
+
end
|
130
|
+
|
131
|
+
def create_openssl_socket(socket)
|
132
|
+
ssl_socket = nil
|
133
|
+
if OpenSSL::SSL.const_defined?("SSLContext")
|
134
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
135
|
+
@context.set_context(ctx)
|
136
|
+
ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ctx)
|
137
|
+
else
|
138
|
+
ssl_socket = OpenSSL::SSL::SSLSocket.new(socket)
|
139
|
+
@context.set_context(ssl_socket)
|
140
|
+
end
|
141
|
+
ssl_socket
|
142
|
+
end
|
143
|
+
|
144
|
+
def debug(str)
|
145
|
+
@debug_dev << str if @debug_dev && str
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
data/lib/httpclient/timeout.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# HTTPClient - HTTP client library.
|
2
|
-
# Copyright (C) 2000-
|
2
|
+
# Copyright (C) 2000-2015 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
|
3
3
|
#
|
4
4
|
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
|
5
5
|
# redistribute it and/or modify it under the same terms of Ruby's license;
|
data/lib/httpclient/util.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# HTTPClient - HTTP client library.
|
2
|
-
# Copyright (C) 2000-
|
2
|
+
# Copyright (C) 2000-2015 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
|
3
3
|
#
|
4
4
|
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
|
5
5
|
# redistribute it and/or modify it under the same terms of Ruby's license;
|
@@ -24,6 +24,28 @@ if RUBY_VERSION < "1.9.3"
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
# With recent JRuby 1.7 + jruby-openssl, X509CRL#extentions_to_text causes
|
28
|
+
# StringIndexOOBException when we try to dump SSL Server Certificate.
|
29
|
+
# when one of extensions has "" as value.
|
30
|
+
if defined?(JRUBY_VERSION)
|
31
|
+
require 'openssl'
|
32
|
+
require 'java'
|
33
|
+
module OpenSSL
|
34
|
+
module X509
|
35
|
+
class Certificate
|
36
|
+
java_import 'java.security.cert.Certificate'
|
37
|
+
java_import 'java.security.cert.CertificateFactory'
|
38
|
+
java_import 'java.io.ByteArrayInputStream'
|
39
|
+
def to_text
|
40
|
+
cf = CertificateFactory.getInstance('X.509')
|
41
|
+
cf.generateCertificate(ByteArrayInputStream.new(self.to_der.to_java_bytes)).toString
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
27
49
|
class HTTPClient
|
28
50
|
|
29
51
|
|
data/lib/httpclient/version.rb
CHANGED
data/lib/oauthclient.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# HTTPClient - HTTP client library.
|
2
|
-
# Copyright (C) 2000-
|
2
|
+
# Copyright (C) 2000-2015 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
|
3
3
|
#
|
4
4
|
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
|
5
5
|
# redistribute it and/or modify it under the same terms of Ruby's license;
|
File without changes
|
data/test/helper.rb
CHANGED
@@ -59,11 +59,13 @@ module Helper
|
|
59
59
|
@client = HTTPClient.new
|
60
60
|
end
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
62
|
+
def escape_noproxy
|
63
|
+
backup = HTTPClient::NO_PROXY_HOSTS.dup
|
64
|
+
HTTPClient::NO_PROXY_HOSTS.clear
|
65
|
+
yield
|
66
|
+
ensure
|
67
|
+
HTTPClient::NO_PROXY_HOSTS.replace(backup)
|
68
|
+
end
|
67
69
|
|
68
70
|
def setup_proxyserver
|
69
71
|
@proxyserver = WEBrick::HTTPProxyServer.new(
|
data/test/test_auth.rb
CHANGED
@@ -124,6 +124,7 @@ class TestAuth < Test::Unit::TestCase
|
|
124
124
|
end
|
125
125
|
# Make it work if @value == nil
|
126
126
|
class SecurityBuffer < FieldSet
|
127
|
+
remove_method(:data_size) if method_defined?(:data_size)
|
127
128
|
def data_size
|
128
129
|
@active && @value ? @value.size : 0
|
129
130
|
end
|
@@ -230,7 +231,7 @@ class TestAuth < Test::Unit::TestCase
|
|
230
231
|
c.www_auth.basic_auth.instance_eval { @scheme = "BASIC" }
|
231
232
|
c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
|
232
233
|
|
233
|
-
|
234
|
+
100.times.map { |idx|
|
234
235
|
Thread.new(idx) { |idx2|
|
235
236
|
Thread.abort_on_exception = true
|
236
237
|
Thread.pass
|
@@ -251,7 +252,7 @@ class TestAuth < Test::Unit::TestCase
|
|
251
252
|
c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
|
252
253
|
c.debug_dev = str = ''
|
253
254
|
c.get_content("http://localhost:#{serverport}/basic_auth/sub/dir/")
|
254
|
-
assert_match
|
255
|
+
assert_match(/Authorization: Basic YWRtaW46YWRtaW4=/, str)
|
255
256
|
end
|
256
257
|
|
257
258
|
def test_digest_auth
|
@@ -267,7 +268,7 @@ class TestAuth < Test::Unit::TestCase
|
|
267
268
|
c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
|
268
269
|
c.debug_dev = str = ''
|
269
270
|
c.get_content("http://localhost:#{serverport}/digest_auth/sub/dir/")
|
270
|
-
assert_match
|
271
|
+
assert_match(/Authorization: Digest/, str)
|
271
272
|
end
|
272
273
|
|
273
274
|
def test_digest_auth_with_block
|
@@ -332,6 +333,16 @@ class TestAuth < Test::Unit::TestCase
|
|
332
333
|
assert_match(/Proxy-Authorization: Basic YWRtaW46YWRtaW4=/, str)
|
333
334
|
end
|
334
335
|
|
336
|
+
def test_proxy_auth_force
|
337
|
+
c = HTTPClient.new
|
338
|
+
c.set_proxy_auth('admin', 'admin')
|
339
|
+
c.force_basic_auth = true
|
340
|
+
c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
|
341
|
+
c.debug_dev = str = ''
|
342
|
+
c.get_content('http://example.com/')
|
343
|
+
assert_match(/Proxy-Authorization: Basic YWRtaW46YWRtaW4=/, str)
|
344
|
+
end
|
345
|
+
|
335
346
|
def test_proxy_auth_reuses_credentials
|
336
347
|
c = HTTPClient.new
|
337
348
|
c.set_proxy_auth('admin', 'admin')
|
@@ -442,11 +453,19 @@ class TestAuth < Test::Unit::TestCase
|
|
442
453
|
end
|
443
454
|
|
444
455
|
def test_basic_auth_post_with_multipart
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
456
|
+
retry_times = 0
|
457
|
+
begin
|
458
|
+
c = HTTPClient.new
|
459
|
+
c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
|
460
|
+
File.open(__FILE__) do |f|
|
461
|
+
# read 'f' twice for authorization negotiation
|
462
|
+
assert_equal('basic_auth OK', c.post("http://localhost:#{serverport}/basic_auth", :file => f).content)
|
463
|
+
end
|
464
|
+
rescue Errno::ECONNRESET, HTTPClient::KeepAliveDisconnected
|
465
|
+
# TODO: WEBrick server returns ECONNRESET/EPIPE before sending Unauthorized response to client?
|
466
|
+
raise if retry_times > 5
|
467
|
+
retry_times += 1
|
468
|
+
retry
|
450
469
|
end
|
451
470
|
end
|
452
471
|
|