httpclient 2.5.3.3 → 2.6.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.
- checksums.yaml +4 -4
- data/bin/httpclient +11 -5
- data/bin/jsonclient +32 -78
- data/lib/httpclient.rb +49 -17
- data/lib/httpclient/auth.rb +60 -87
- data/lib/httpclient/cookie.rb +160 -388
- data/lib/httpclient/http.rb +40 -11
- data/lib/httpclient/session.rb +6 -22
- data/lib/httpclient/version.rb +1 -1
- data/lib/httpclient/webagent-cookie.rb +459 -0
- data/lib/jsonclient.rb +63 -0
- data/test/test_auth.rb +51 -6
- data/test/test_cookie.rb +128 -231
- data/test/test_http-access2.rb +6 -8
- data/test/test_httpclient.rb +96 -33
- data/test/test_jsonclient.rb +80 -0
- data/test/test_webagent-cookie.rb +465 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6c0658e8a69a8fc6b9bd591912d99dfdb01aeb0
|
4
|
+
data.tar.gz: e513505c66b946b6c3dd2fb3b60a3f9b9252b76c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aca638628efee8a54e2a6747db133232be76f355b892f89f4816790180955019aa1edfc9d3426b97988e6fa51fbc19eb2b7735c4c6ab8b570bb166678beccfd6
|
7
|
+
data.tar.gz: 02ec73e1b3ae1edf0dd0fe5f6e070de3f8b4a309066e1ce8f2b945ed4d53d532a2bfd513374ce1dfd793862221b57e172c21e4cc4166b32b811409d773e74af7
|
data/bin/httpclient
CHANGED
@@ -12,12 +12,18 @@
|
|
12
12
|
require 'httpclient'
|
13
13
|
|
14
14
|
METHODS = ['head', 'get', 'post', 'put', 'delete', 'options', 'propfind', 'proppatch', 'trace']
|
15
|
-
|
15
|
+
method = ARGV.shift
|
16
|
+
url = ARGV.shift
|
17
|
+
if method && url
|
16
18
|
client = HTTPClient.new
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
if method == 'download'
|
20
|
+
print client.get_content(url)
|
21
|
+
else
|
22
|
+
client.debug_dev = STDERR
|
23
|
+
$DEBUG = true
|
24
|
+
require 'pp'
|
25
|
+
pp client.send(*ARGV)
|
26
|
+
end
|
21
27
|
exit
|
22
28
|
end
|
23
29
|
|
data/bin/jsonclient
CHANGED
@@ -1,98 +1,52 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
#
|
3
|
+
# jsonclient shell command.
|
4
4
|
#
|
5
|
-
# Usage: 1) %
|
6
|
-
# Usage: 2) %
|
5
|
+
# Usage: 1) % jsonclient post https://www.example.com/ content.json
|
6
|
+
# Usage: 2) % jsonclient
|
7
7
|
#
|
8
8
|
# For 1) it issues a GET request to the given URI and shows the wiredump and
|
9
9
|
# the parsed result. For 2) it invokes irb shell with the binding that has a
|
10
|
-
#
|
11
|
-
# >
|
12
|
-
require '
|
13
|
-
require 'json'
|
10
|
+
# JSONClient as 'self'. You can call JSONClient instance methods like;
|
11
|
+
# > post "https://www.example.com/resource", {'hello' => 'world'}
|
12
|
+
require 'jsonclient'
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
original_content
|
24
|
-
end
|
25
|
-
end
|
14
|
+
method = ARGV.shift
|
15
|
+
url = ARGV.shift
|
16
|
+
body = []
|
17
|
+
if ['post', 'put'].include?(method)
|
18
|
+
if ARGV.size == 1 && File.exist?(ARGV[0])
|
19
|
+
body << File.read(ARGV[0])
|
20
|
+
else
|
21
|
+
body << ARGF.read
|
26
22
|
end
|
27
23
|
end
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
@client = client
|
41
|
-
@replace = false
|
42
|
-
end
|
43
|
-
|
44
|
-
def filter_request(req)
|
45
|
-
req.header['content-type'] = @client.content_type_json if @replace
|
46
|
-
end
|
47
|
-
|
48
|
-
def filter_response(req, res)
|
49
|
-
@replace = false
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def initialize(*args)
|
54
|
-
super
|
55
|
-
@header_filter = JSONRequestHeaderFilter.new(self)
|
56
|
-
@request_filter << @header_filter
|
57
|
-
@content_type_json = 'application/json; charset=utf-8'
|
58
|
-
end
|
59
|
-
|
60
|
-
def post(uri, *args, &block)
|
61
|
-
@header_filter.replace = true
|
62
|
-
request(:post, uri, jsonify(argument_to_hash(args, :body, :header, :follow_redirect)), &block)
|
63
|
-
end
|
64
|
-
|
65
|
-
def put(uri, *args, &block)
|
66
|
-
@header_filter.replace = true
|
67
|
-
request(:put, uri, jsonify(argument_to_hash(args, :body, :header)), &block)
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
def jsonify(hash)
|
73
|
-
if hash[:body] && hash[:body].is_a?(Hash)
|
74
|
-
hash[:body] = JSON.generate(hash[:body])
|
24
|
+
if method && url
|
25
|
+
require 'pp'
|
26
|
+
client = JSONClient.new
|
27
|
+
client.debug_dev = STDERR if $DEBUG
|
28
|
+
res = client.send(method, url, *body)
|
29
|
+
STDERR.puts('RESPONSE HEADER: ')
|
30
|
+
PP.pp(res.headers, STDERR)
|
31
|
+
if res.ok?
|
32
|
+
begin
|
33
|
+
puts JSON.pretty_generate(res.content)
|
34
|
+
rescue JSON::GeneratorError
|
35
|
+
puts res.content
|
75
36
|
end
|
76
|
-
|
37
|
+
exit 0
|
38
|
+
else
|
39
|
+
STDERR.puts res.content
|
40
|
+
exit 1
|
77
41
|
end
|
78
42
|
end
|
79
43
|
|
80
|
-
METHODS = ['head', 'get', 'post', 'put', 'delete', 'options', 'propfind', 'proppatch', 'trace']
|
81
|
-
if ARGV.size >= 2 && METHODS.include?(ARGV[0])
|
82
|
-
client = JSONClient.new
|
83
|
-
client.debug_dev = STDERR
|
84
|
-
$DEBUG = true
|
85
|
-
require 'pp'
|
86
|
-
pp client.send(*ARGV)
|
87
|
-
exit
|
88
|
-
end
|
89
|
-
|
90
44
|
require 'irb'
|
91
45
|
require 'irb/completion'
|
92
46
|
|
93
47
|
class Runner
|
94
48
|
def initialize
|
95
|
-
@httpclient =
|
49
|
+
@httpclient = JSONClient.new
|
96
50
|
end
|
97
51
|
|
98
52
|
def method_missing(msg, *a, &b)
|
@@ -124,7 +78,7 @@ class Runner
|
|
124
78
|
end
|
125
79
|
|
126
80
|
def to_s
|
127
|
-
'
|
81
|
+
'JSONClient'
|
128
82
|
end
|
129
83
|
end
|
130
84
|
|
data/lib/httpclient.rb
CHANGED
@@ -308,7 +308,7 @@ class HTTPClient
|
|
308
308
|
|
309
309
|
# HTTPClient::SSLConfig:: SSL configurator.
|
310
310
|
attr_reader :ssl_config
|
311
|
-
#
|
311
|
+
# HTTPClient::CookieManager:: Cookies configurator.
|
312
312
|
attr_accessor :cookie_manager
|
313
313
|
# An array of response HTTP message body String which is used for loop-back
|
314
314
|
# test. See test/* to see how to use it. If you want to do loop-back test
|
@@ -415,7 +415,7 @@ class HTTPClient
|
|
415
415
|
@session_manager.agent_name = agent_name || DEFAULT_AGENT_NAME
|
416
416
|
@session_manager.from = from
|
417
417
|
@session_manager.ssl_config = @ssl_config = SSLConfig.new(self)
|
418
|
-
@cookie_manager =
|
418
|
+
@cookie_manager = CookieManager.new
|
419
419
|
@follow_redirect_count = 10
|
420
420
|
load_environment
|
421
421
|
self.proxy = proxy if proxy
|
@@ -576,7 +576,6 @@ class HTTPClient
|
|
576
576
|
|
577
577
|
# Try to save Cookies to the file specified in set_cookie_store. Unexpected
|
578
578
|
# error will be raised if you don't call set_cookie_store first.
|
579
|
-
# (interface mismatch between WebAgent::CookieManager implementation)
|
580
579
|
def save_cookie_store
|
581
580
|
@cookie_manager.save_cookies
|
582
581
|
end
|
@@ -927,6 +926,11 @@ class HTTPClient
|
|
927
926
|
private
|
928
927
|
|
929
928
|
class RetryableResponse < StandardError # :nodoc:
|
929
|
+
attr_reader :res
|
930
|
+
|
931
|
+
def initialize(res = nil)
|
932
|
+
@res = res
|
933
|
+
end
|
930
934
|
end
|
931
935
|
|
932
936
|
class KeepAliveDisconnected < StandardError # :nodoc:
|
@@ -947,24 +951,37 @@ private
|
|
947
951
|
end
|
948
952
|
|
949
953
|
def do_request(method, uri, query, body, header, &block)
|
950
|
-
conn = Connection.new
|
951
954
|
res = nil
|
952
955
|
if HTTP::Message.file?(body)
|
953
956
|
pos = body.pos rescue nil
|
954
957
|
end
|
955
958
|
retry_count = @session_manager.protocol_retry_count
|
956
959
|
proxy = no_proxy?(uri) ? nil : @proxy
|
960
|
+
previous_request = previous_response = nil
|
957
961
|
while retry_count > 0
|
958
962
|
body.pos = pos if pos
|
959
963
|
req = create_request(method, uri, query, body, header)
|
964
|
+
if previous_request
|
965
|
+
# to remember IO positions to read
|
966
|
+
req.http_body.positions = previous_request.http_body.positions
|
967
|
+
end
|
960
968
|
begin
|
961
969
|
protect_keep_alive_disconnected do
|
962
|
-
|
970
|
+
# TODO: remove Connection.new
|
971
|
+
# We want to delete Connection usage in do_get_block but Newrelic gem depends on it.
|
972
|
+
# https://github.com/newrelic/rpm/blob/master/lib/new_relic/agent/instrumentation/httpclient.rb#L34-L36
|
973
|
+
conn = Connection.new
|
974
|
+
res = do_get_block(req, proxy, conn, &block)
|
975
|
+
# Webmock's do_get_block returns ConditionVariable
|
976
|
+
if !res.respond_to?(:previous)
|
977
|
+
res = conn.pop
|
978
|
+
end
|
963
979
|
end
|
964
|
-
res =
|
980
|
+
res.previous = previous_response
|
965
981
|
break
|
966
|
-
rescue RetryableResponse
|
967
|
-
|
982
|
+
rescue RetryableResponse => e
|
983
|
+
previous_request = req
|
984
|
+
previous_response = res = e.res
|
968
985
|
retry_count -= 1
|
969
986
|
end
|
970
987
|
end
|
@@ -1029,15 +1046,21 @@ private
|
|
1029
1046
|
pos = body.pos rescue nil
|
1030
1047
|
end
|
1031
1048
|
retry_number = 0
|
1049
|
+
previous = nil
|
1050
|
+
request_query = query
|
1032
1051
|
while retry_number < @follow_redirect_count
|
1033
1052
|
body.pos = pos if pos
|
1034
|
-
res = do_request(method, uri,
|
1053
|
+
res = do_request(method, uri, request_query, body, header, &filtered_block)
|
1054
|
+
res.previous = previous
|
1035
1055
|
if res.redirect?
|
1036
1056
|
if res.header['location'].empty?
|
1037
1057
|
raise BadResponseError.new("Missing Location header for redirect", res)
|
1038
1058
|
end
|
1039
1059
|
method = :get if res.see_other? # See RFC2616 10.3.4
|
1040
1060
|
uri = urify(@redirect_uri_callback.call(uri, res))
|
1061
|
+
# To avoid duped query parameter. 'location' must include query part.
|
1062
|
+
request_query = nil
|
1063
|
+
previous = res
|
1041
1064
|
retry_number += 1
|
1042
1065
|
else
|
1043
1066
|
return res
|
@@ -1058,10 +1081,13 @@ private
|
|
1058
1081
|
begin
|
1059
1082
|
yield
|
1060
1083
|
rescue KeepAliveDisconnected => e
|
1061
|
-
|
1062
|
-
|
1084
|
+
# Force to create new connection
|
1085
|
+
Thread.current[:HTTPClient_AcquireNewConnection] = true
|
1086
|
+
begin
|
1087
|
+
yield
|
1088
|
+
ensure
|
1089
|
+
Thread.current[:HTTPClient_AcquireNewConnection] = false
|
1063
1090
|
end
|
1064
|
-
yield
|
1065
1091
|
end
|
1066
1092
|
end
|
1067
1093
|
|
@@ -1101,8 +1127,11 @@ private
|
|
1101
1127
|
header.each do |key, value|
|
1102
1128
|
req.header.add(key.to_s, value)
|
1103
1129
|
end
|
1104
|
-
if @cookie_manager
|
1105
|
-
|
1130
|
+
if @cookie_manager
|
1131
|
+
cookie_value = @cookie_manager.cookie_value(uri)
|
1132
|
+
if cookie_value
|
1133
|
+
req.header.add('Cookie', cookie_value)
|
1134
|
+
end
|
1106
1135
|
end
|
1107
1136
|
req
|
1108
1137
|
end
|
@@ -1152,8 +1181,9 @@ private
|
|
1152
1181
|
end
|
1153
1182
|
if str = @test_loopback_response.shift
|
1154
1183
|
dump_dummy_request_response(req.http_body.dump, str) if @debug_dev
|
1155
|
-
|
1156
|
-
|
1184
|
+
res = HTTP::Message.new_response(str, req.header)
|
1185
|
+
conn.push(res)
|
1186
|
+
return res
|
1157
1187
|
end
|
1158
1188
|
content = block ? nil : ''
|
1159
1189
|
res = HTTP::Message.new_response(content, req.header)
|
@@ -1178,8 +1208,9 @@ private
|
|
1178
1208
|
filter.filter_response(req, res)
|
1179
1209
|
}
|
1180
1210
|
if commands.find { |command| command == :retry }
|
1181
|
-
raise RetryableResponse.new
|
1211
|
+
raise RetryableResponse.new(res)
|
1182
1212
|
end
|
1213
|
+
res
|
1183
1214
|
end
|
1184
1215
|
|
1185
1216
|
def do_get_stream(req, proxy, conn)
|
@@ -1209,6 +1240,7 @@ private
|
|
1209
1240
|
filter.filter_response(req, res)
|
1210
1241
|
}
|
1211
1242
|
# ignore commands (not retryable in async mode)
|
1243
|
+
res
|
1212
1244
|
end
|
1213
1245
|
|
1214
1246
|
def do_get_header(req, res, sess)
|
data/lib/httpclient/auth.rb
CHANGED
@@ -95,6 +95,13 @@ class HTTPClient
|
|
95
95
|
@authenticator.each do |auth|
|
96
96
|
next unless auth.set? # hasn't be set, don't use it
|
97
97
|
if cred = auth.get(req)
|
98
|
+
if cred == :skip
|
99
|
+
# some authenticator (NTLM and Negotiate) does not
|
100
|
+
# need to send extra header after authorization. In such case
|
101
|
+
# it should block other authenticators to respond and :skip is
|
102
|
+
# the marker for such case.
|
103
|
+
return
|
104
|
+
end
|
98
105
|
req.header.set('Authorization', auth.scheme + " " + cred)
|
99
106
|
return
|
100
107
|
end
|
@@ -179,6 +186,13 @@ class HTTPClient
|
|
179
186
|
@authenticator.each do |auth|
|
180
187
|
next unless auth.set? # hasn't be set, don't use it
|
181
188
|
if cred = auth.get(req)
|
189
|
+
if cred == :skip
|
190
|
+
# some authenticator (NTLM and Negotiate) does not
|
191
|
+
# need to send extra header after authorization. In such case
|
192
|
+
# it should block other authenticators to respond and :skip is
|
193
|
+
# the marker for such case.
|
194
|
+
return
|
195
|
+
end
|
182
196
|
req.header.set('Proxy-Authorization', auth.scheme + " " + cred)
|
183
197
|
return
|
184
198
|
end
|
@@ -208,36 +222,43 @@ class HTTPClient
|
|
208
222
|
end
|
209
223
|
end
|
210
224
|
|
211
|
-
# Authentication filter
|
212
|
-
|
213
|
-
class BasicAuth
|
225
|
+
# Authentication filter base class.
|
226
|
+
class AuthBase
|
214
227
|
include HTTPClient::Util
|
215
|
-
include Mutex_m
|
216
228
|
|
217
229
|
# Authentication scheme.
|
218
230
|
attr_reader :scheme
|
219
231
|
|
232
|
+
def initialize(scheme)
|
233
|
+
@scheme = scheme
|
234
|
+
@challenge = {}
|
235
|
+
end
|
236
|
+
|
237
|
+
# Resets challenge state. Do not send '*Authorization' header until the
|
238
|
+
# server sends '*Authentication' again.
|
239
|
+
def reset_challenge
|
240
|
+
synchronize do
|
241
|
+
@challenge.clear
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Authentication filter for handling BasicAuth negotiation.
|
247
|
+
# Used in WWWAuth and ProxyAuth.
|
248
|
+
class BasicAuth < AuthBase
|
249
|
+
include Mutex_m
|
250
|
+
|
220
251
|
# Send Authorization Header without receiving 401
|
221
252
|
attr_accessor :force_auth
|
222
253
|
|
223
254
|
# Creates new BasicAuth filter.
|
224
255
|
def initialize
|
225
|
-
super
|
256
|
+
super('Basic')
|
226
257
|
@cred = nil
|
227
258
|
@auth = {}
|
228
|
-
@challenge = {}
|
229
|
-
@scheme = "Basic"
|
230
259
|
@force_auth = false
|
231
260
|
end
|
232
261
|
|
233
|
-
# Resets challenge state. Do not send '*Authorization' header until the
|
234
|
-
# server sends '*Authentication' again.
|
235
|
-
def reset_challenge
|
236
|
-
synchronize {
|
237
|
-
@challenge.clear
|
238
|
-
}
|
239
|
-
end
|
240
|
-
|
241
262
|
# Set authentication credential.
|
242
263
|
# uri == nil for generic purpose (allow to use user/password for any URL).
|
243
264
|
def set(uri, user, passwd)
|
@@ -283,7 +304,6 @@ class HTTPClient
|
|
283
304
|
end
|
284
305
|
|
285
306
|
class ProxyBasicAuth < BasicAuth
|
286
|
-
|
287
307
|
def set(uri, user, passwd)
|
288
308
|
synchronize do
|
289
309
|
@cred = ["#{user}:#{passwd}"].pack('m').tr("\n", '')
|
@@ -308,27 +328,14 @@ class HTTPClient
|
|
308
328
|
|
309
329
|
# Authentication filter for handling DigestAuth negotiation.
|
310
330
|
# Used in WWWAuth.
|
311
|
-
class DigestAuth
|
331
|
+
class DigestAuth < AuthBase
|
312
332
|
include Mutex_m
|
313
333
|
|
314
|
-
# Authentication scheme.
|
315
|
-
attr_reader :scheme
|
316
|
-
|
317
334
|
# Creates new DigestAuth filter.
|
318
335
|
def initialize
|
319
|
-
super
|
336
|
+
super('Digest')
|
320
337
|
@auth = {}
|
321
|
-
@challenge = {}
|
322
338
|
@nonce_count = 0
|
323
|
-
@scheme = "Digest"
|
324
|
-
end
|
325
|
-
|
326
|
-
# Resets challenge state. Do not send '*Authorization' header until the
|
327
|
-
# server sends '*Authentication' again.
|
328
|
-
def reset_challenge
|
329
|
-
synchronize do
|
330
|
-
@challenge.clear
|
331
|
-
end
|
332
339
|
end
|
333
340
|
|
334
341
|
# Set authentication credential.
|
@@ -483,41 +490,28 @@ class HTTPClient
|
|
483
490
|
true
|
484
491
|
}
|
485
492
|
end
|
486
|
-
|
487
493
|
end
|
488
494
|
|
489
495
|
# Authentication filter for handling Negotiate/NTLM negotiation.
|
490
496
|
# Used in WWWAuth and ProxyAuth.
|
491
497
|
#
|
492
498
|
# NegotiateAuth depends on 'ruby/ntlm' module.
|
493
|
-
class NegotiateAuth
|
499
|
+
class NegotiateAuth < AuthBase
|
494
500
|
include Mutex_m
|
495
501
|
|
496
|
-
# Authentication scheme.
|
497
|
-
attr_reader :scheme
|
498
502
|
# NTLM opt for ruby/ntlm. {:ntlmv2 => true} by default.
|
499
503
|
attr_reader :ntlm_opt
|
500
504
|
|
501
505
|
# Creates new NegotiateAuth filter.
|
502
506
|
def initialize(scheme = "Negotiate")
|
503
|
-
super()
|
507
|
+
super(scheme)
|
504
508
|
@auth = {}
|
505
509
|
@auth_default = nil
|
506
|
-
@challenge = {}
|
507
|
-
@scheme = scheme
|
508
510
|
@ntlm_opt = {
|
509
511
|
:ntlmv2 => true
|
510
512
|
}
|
511
513
|
end
|
512
514
|
|
513
|
-
# Resets challenge state. Do not send '*Authorization' header until the
|
514
|
-
# server sends '*Authentication' again.
|
515
|
-
def reset_challenge
|
516
|
-
synchronize do
|
517
|
-
@challenge.clear
|
518
|
-
end
|
519
|
-
end
|
520
|
-
|
521
515
|
# Set authentication credential.
|
522
516
|
# uri == nil for generic purpose (allow to use user/password for any URL).
|
523
517
|
def set(uri, user, passwd)
|
@@ -561,16 +555,19 @@ class HTTPClient
|
|
561
555
|
when :init
|
562
556
|
t1 = Net::NTLM::Message::Type1.new
|
563
557
|
t1.domain = domain if domain
|
564
|
-
|
558
|
+
t1.encode64
|
565
559
|
when :response
|
566
560
|
t2 = Net::NTLM::Message.decode64(authphrase)
|
567
561
|
param = {:user => user, :password => passwd}
|
568
562
|
param[:domain] = domain if domain
|
569
563
|
t3 = t2.response(param, @ntlm_opt.dup)
|
570
|
-
@challenge
|
571
|
-
|
564
|
+
@challenge[target_uri][:state] = :done
|
565
|
+
t3.encode64
|
566
|
+
when :done
|
567
|
+
:skip
|
568
|
+
else
|
569
|
+
nil
|
572
570
|
end
|
573
|
-
nil
|
574
571
|
}
|
575
572
|
end
|
576
573
|
|
@@ -596,25 +593,12 @@ class HTTPClient
|
|
596
593
|
# Used in ProxyAuth.
|
597
594
|
#
|
598
595
|
# SSPINegotiateAuth depends on 'win32/sspi' module.
|
599
|
-
class SSPINegotiateAuth
|
596
|
+
class SSPINegotiateAuth < AuthBase
|
600
597
|
include Mutex_m
|
601
598
|
|
602
|
-
# Authentication scheme.
|
603
|
-
attr_reader :scheme
|
604
|
-
|
605
599
|
# Creates new SSPINegotiateAuth filter.
|
606
600
|
def initialize
|
607
|
-
super
|
608
|
-
@challenge = {}
|
609
|
-
@scheme = "Negotiate"
|
610
|
-
end
|
611
|
-
|
612
|
-
# Resets challenge state. Do not send '*Authorization' header until the
|
613
|
-
# server sends '*Authentication' again.
|
614
|
-
def reset_challenge
|
615
|
-
synchronize do
|
616
|
-
@challenge.clear
|
617
|
-
end
|
601
|
+
super('Negotiate')
|
618
602
|
end
|
619
603
|
|
620
604
|
# Set authentication credential.
|
@@ -646,21 +630,24 @@ class HTTPClient
|
|
646
630
|
when :init
|
647
631
|
if defined?(Win32::SSPI)
|
648
632
|
authenticator = param[:authenticator] = Win32::SSPI::NegotiateAuth.new
|
649
|
-
|
633
|
+
authenticator.get_initial_token(@scheme)
|
650
634
|
else # use GSSAPI
|
651
635
|
authenticator = param[:authenticator] = GSSAPI::Simple.new(domain_uri.host, 'HTTP')
|
652
636
|
# Base64 encode the context token
|
653
|
-
|
637
|
+
[authenticator.init_context].pack('m').gsub(/\n/,'')
|
654
638
|
end
|
655
639
|
when :response
|
656
|
-
@challenge
|
640
|
+
@challenge[target_uri][:state] = :done
|
657
641
|
if defined?(Win32::SSPI)
|
658
|
-
|
642
|
+
authenticator.complete_authentication(authphrase)
|
659
643
|
else # use GSSAPI
|
660
|
-
|
644
|
+
authenticator.init_context(authphrase.unpack('m').pop)
|
661
645
|
end
|
646
|
+
when :done
|
647
|
+
:skip
|
648
|
+
else
|
649
|
+
nil
|
662
650
|
end
|
663
|
-
nil
|
664
651
|
}
|
665
652
|
end
|
666
653
|
|
@@ -692,13 +679,9 @@ class HTTPClient
|
|
692
679
|
# CAUTION: This impl does NOT support OAuth Request Body Hash spec for now.
|
693
680
|
# http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html
|
694
681
|
#
|
695
|
-
class OAuth
|
696
|
-
include HTTPClient::Util
|
682
|
+
class OAuth < AuthBase
|
697
683
|
include Mutex_m
|
698
684
|
|
699
|
-
# Authentication scheme.
|
700
|
-
attr_reader :scheme
|
701
|
-
|
702
685
|
class Config
|
703
686
|
include HTTPClient::Util
|
704
687
|
|
@@ -768,23 +751,13 @@ class HTTPClient
|
|
768
751
|
|
769
752
|
# Creates new DigestAuth filter.
|
770
753
|
def initialize
|
771
|
-
super
|
754
|
+
super('OAuth')
|
772
755
|
@config = nil # common config
|
773
756
|
@auth = {} # configs for each site
|
774
|
-
@challenge = {}
|
775
757
|
@nonce_count = 0
|
776
758
|
@signature_handler = {
|
777
759
|
'HMAC-SHA1' => method(:sign_hmac_sha1)
|
778
760
|
}
|
779
|
-
@scheme = "OAuth"
|
780
|
-
end
|
781
|
-
|
782
|
-
# Resets challenge state. Do not send '*Authorization' header until the
|
783
|
-
# server sends '*Authentication' again.
|
784
|
-
def reset_challenge
|
785
|
-
synchronize do
|
786
|
-
@challenge.clear
|
787
|
-
end
|
788
761
|
end
|
789
762
|
|
790
763
|
# Set authentication credential.
|