httpclient 2.5.3.3 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|