httpclient 2.5.1 → 2.5.2
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/lib/httpclient.rb +47 -21
- data/lib/httpclient/auth.rb +5 -1
- data/lib/httpclient/include_client.rb +2 -0
- data/lib/httpclient/session.rb +7 -7
- data/lib/httpclient/version.rb +1 -1
- data/test/test_auth.rb +37 -0
- data/test/test_http-access2.rb +2 -2
- data/test/test_httpclient.rb +55 -2
- data/test/test_ssl.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96ac0d88857cdda17631e5d2f8d5055854324813
|
4
|
+
data.tar.gz: d481af07b3a540d43044a9065e47ea177d5f3aa7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd7ee572d2081458053de5bcd27408848067abc83dfbf8be88b78740bac06692a504eaf16a0418e47ea1555170825a4740505581b3ddc24706f557ef1f2bc3a1
|
7
|
+
data.tar.gz: cd0a8f4fa967737b90d40bd073e0f0c7e264d2e1b5873342337abc3dc32caa9884e597d40675753d6458472f05cc560380aa955b1af62c9672013c71bf16cce8
|
data/lib/httpclient.rb
CHANGED
@@ -324,6 +324,8 @@ class HTTPClient
|
|
324
324
|
# How many times get_content and post_content follows HTTP redirect.
|
325
325
|
# 10 by default.
|
326
326
|
attr_accessor :follow_redirect_count
|
327
|
+
# Base url of resources.
|
328
|
+
attr_accessor :base_url
|
327
329
|
|
328
330
|
# Set HTTP version as a String:: 'HTTP/1.0' or 'HTTP/1.1'
|
329
331
|
attr_proxy(:protocol_version, true)
|
@@ -362,27 +364,36 @@ class HTTPClient
|
|
362
364
|
|
363
365
|
# Creates a HTTPClient instance which manages sessions, cookies, etc.
|
364
366
|
#
|
365
|
-
# HTTPClient.new takes
|
366
|
-
#
|
367
|
-
#
|
368
|
-
#
|
367
|
+
# HTTPClient.new takes optional arguments as a Hash.
|
368
|
+
# * :proxy - proxy url string
|
369
|
+
# * :agent_name - User-Agent String
|
370
|
+
# * :from - from header String
|
371
|
+
# * :base_url - base URL of resources
|
372
|
+
# * :force_basic_auth - flag for sending Authorization header w/o gettin 401 first
|
373
|
+
# User-Agent and From are embedded in HTTP request Header if given.
|
374
|
+
# From header is not set without setting it explicitly.
|
369
375
|
#
|
370
376
|
# proxy = 'http://myproxy:8080'
|
371
377
|
# agent_name = 'MyAgent/0.1'
|
372
378
|
# from = 'from@example.com'
|
373
379
|
# HTTPClient.new(proxy, agent_name, from)
|
374
380
|
#
|
375
|
-
#
|
376
|
-
#
|
381
|
+
# After you set base_url, all resources you pass to get, post and other
|
382
|
+
# methods are recognized to be prefixed with base_url. Say base_url is
|
383
|
+
# 'https://api.example.com/v1, get('/users') is the same as
|
384
|
+
# get('https://api.example.com/v1/users') internally. You can also pass
|
385
|
+
# full URL from 'http://' even after setting base_url.
|
377
386
|
#
|
378
|
-
# HTTPClient.new(:agent_name => 'MyAgent/0.1')
|
379
387
|
def initialize(*args)
|
380
|
-
proxy, agent_name, from
|
388
|
+
proxy, agent_name, from, base_url, force_basic_auth =
|
389
|
+
keyword_argument(args, :proxy, :agent_name, :from, :base_url, :force_basic_auth)
|
381
390
|
@proxy = nil # assigned later.
|
382
391
|
@no_proxy = nil
|
383
392
|
@no_proxy_regexps = []
|
393
|
+
@base_url = base_url
|
384
394
|
@www_auth = WWWAuth.new
|
385
395
|
@proxy_auth = ProxyAuth.new
|
396
|
+
@www_auth.basic_auth.force_auth = @proxy_auth.basic_auth.force_auth = force_basic_auth
|
386
397
|
@request_filter = [@proxy_auth, @www_auth]
|
387
398
|
@debug_dev = nil
|
388
399
|
@redirect_uri_callback = method(:default_redirect_uri_callback)
|
@@ -509,14 +520,14 @@ class HTTPClient
|
|
509
520
|
#
|
510
521
|
# Calling this method resets all existing sessions.
|
511
522
|
def set_auth(domain, user, passwd)
|
512
|
-
uri =
|
523
|
+
uri = to_resource_url(domain)
|
513
524
|
@www_auth.set_auth(uri, user, passwd)
|
514
525
|
reset_all
|
515
526
|
end
|
516
527
|
|
517
528
|
# Deprecated. Use set_auth instead.
|
518
529
|
def set_basic_auth(domain, user, passwd)
|
519
|
-
uri =
|
530
|
+
uri = to_resource_url(domain)
|
520
531
|
@www_auth.basic_auth.set(uri, user, passwd)
|
521
532
|
reset_all
|
522
533
|
end
|
@@ -531,6 +542,14 @@ class HTTPClient
|
|
531
542
|
reset_all
|
532
543
|
end
|
533
544
|
|
545
|
+
# Turn on/off the BasicAuth force flag. Generally HTTP client must
|
546
|
+
# send Authorization header after it gets 401 error from server from
|
547
|
+
# security reason. But in some situation (e.g. API client) you might
|
548
|
+
# want to send Authorization from the beginning.
|
549
|
+
def force_basic_auth=(force_basic_auth)
|
550
|
+
@www_auth.basic_auth.force_auth = @proxy_auth.basic_auth.force_auth = force_basic_auth
|
551
|
+
end
|
552
|
+
|
534
553
|
# Sets the filename where non-volatile Cookies be saved by calling
|
535
554
|
# save_cookie_store.
|
536
555
|
# This method tries to load and managing Cookies from the specified file.
|
@@ -778,7 +797,7 @@ class HTTPClient
|
|
778
797
|
else
|
779
798
|
header ||= {}
|
780
799
|
end
|
781
|
-
uri =
|
800
|
+
uri = to_resource_url(uri)
|
782
801
|
if block
|
783
802
|
if block.arity == 1
|
784
803
|
filtered_block = proc { |res, str|
|
@@ -798,15 +817,13 @@ class HTTPClient
|
|
798
817
|
# Sends HEAD request in async style. See request_async for arguments.
|
799
818
|
# It immediately returns a HTTPClient::Connection instance as a result.
|
800
819
|
def head_async(uri, *args)
|
801
|
-
|
802
|
-
request_async(:head, uri, query, nil, header || {})
|
820
|
+
request_async2(:head, uri, argument_to_hash(args, :query, :header))
|
803
821
|
end
|
804
822
|
|
805
823
|
# Sends GET request in async style. See request_async for arguments.
|
806
824
|
# It immediately returns a HTTPClient::Connection instance as a result.
|
807
825
|
def get_async(uri, *args)
|
808
|
-
|
809
|
-
request_async(:get, uri, query, nil, header || {})
|
826
|
+
request_async2(:get, uri, argument_to_hash(args, :query, :header))
|
810
827
|
end
|
811
828
|
|
812
829
|
# Sends POST request in async style. See request_async for arguments.
|
@@ -866,7 +883,7 @@ class HTTPClient
|
|
866
883
|
#
|
867
884
|
# Arguments definition is the same as request.
|
868
885
|
def request_async(method, uri, query = nil, body = nil, header = {})
|
869
|
-
uri =
|
886
|
+
uri = to_resource_url(uri)
|
870
887
|
do_request_async(method, uri, query, body, header)
|
871
888
|
end
|
872
889
|
|
@@ -881,14 +898,14 @@ class HTTPClient
|
|
881
898
|
else
|
882
899
|
header ||= {}
|
883
900
|
end
|
884
|
-
uri =
|
901
|
+
uri = to_resource_url(uri)
|
885
902
|
do_request_async(method, uri, query, body, header)
|
886
903
|
end
|
887
904
|
|
888
905
|
# Resets internal session for the given URL. Keep-alive connection for the
|
889
906
|
# site (host-port pair) is disconnected if exists.
|
890
907
|
def reset(uri)
|
891
|
-
uri =
|
908
|
+
uri = to_resource_url(uri)
|
892
909
|
@session_manager.reset(uri)
|
893
910
|
end
|
894
911
|
|
@@ -965,8 +982,8 @@ private
|
|
965
982
|
retry_count -= 1
|
966
983
|
end
|
967
984
|
end
|
968
|
-
rescue Exception
|
969
|
-
conn.push
|
985
|
+
rescue Exception => e
|
986
|
+
conn.push e
|
970
987
|
end
|
971
988
|
}
|
972
989
|
conn.async_thread = t
|
@@ -992,7 +1009,7 @@ private
|
|
992
1009
|
end
|
993
1010
|
|
994
1011
|
def follow_redirect(method, uri, query, body, header, &block)
|
995
|
-
uri =
|
1012
|
+
uri = to_resource_url(uri)
|
996
1013
|
if block
|
997
1014
|
filtered_block = proc { |r, str|
|
998
1015
|
block.call(str) if r.ok?
|
@@ -1201,4 +1218,13 @@ private
|
|
1201
1218
|
def set_encoding(str, encoding)
|
1202
1219
|
str.force_encoding(encoding) if encoding
|
1203
1220
|
end
|
1221
|
+
|
1222
|
+
def to_resource_url(uri)
|
1223
|
+
u = urify(uri)
|
1224
|
+
if @base_url && u.scheme.nil? && u.host.nil?
|
1225
|
+
urify(@base_url + uri)
|
1226
|
+
else
|
1227
|
+
u
|
1228
|
+
end
|
1229
|
+
end
|
1204
1230
|
end
|
data/lib/httpclient/auth.rb
CHANGED
@@ -217,6 +217,9 @@ class HTTPClient
|
|
217
217
|
# Authentication scheme.
|
218
218
|
attr_reader :scheme
|
219
219
|
|
220
|
+
# Send Authorization Header without receiving 401
|
221
|
+
attr_accessor :force_auth
|
222
|
+
|
220
223
|
# Creates new BasicAuth filter.
|
221
224
|
def initialize
|
222
225
|
super
|
@@ -224,6 +227,7 @@ class HTTPClient
|
|
224
227
|
@auth = {}
|
225
228
|
@challenge = {}
|
226
229
|
@scheme = "Basic"
|
230
|
+
@force_auth = false
|
227
231
|
end
|
228
232
|
|
229
233
|
# Resets challenge state. Do not send '*Authorization' header until the
|
@@ -259,7 +263,7 @@ class HTTPClient
|
|
259
263
|
def get(req)
|
260
264
|
target_uri = req.header.request_uri
|
261
265
|
synchronize {
|
262
|
-
return nil
|
266
|
+
return nil if !@force_auth and !@challenge.any? { |uri, ok|
|
263
267
|
Util.uri_part_of(target_uri, uri) and ok
|
264
268
|
}
|
265
269
|
return @cred if @cred
|
data/lib/httpclient/session.rb
CHANGED
@@ -38,8 +38,8 @@ class HTTPClient
|
|
38
38
|
# Creates a new Site based on the given URI.
|
39
39
|
def initialize(uri = nil)
|
40
40
|
if uri
|
41
|
-
@scheme = uri.scheme
|
42
|
-
@host = uri.hostname
|
41
|
+
@scheme = uri.scheme || 'tcp'
|
42
|
+
@host = uri.hostname || '0.0.0.0'
|
43
43
|
@port = uri.port.to_i
|
44
44
|
else
|
45
45
|
@scheme = 'tcp'
|
@@ -623,10 +623,10 @@ class HTTPClient
|
|
623
623
|
rescue HTTPClient::TimeoutError
|
624
624
|
close
|
625
625
|
raise
|
626
|
-
rescue
|
626
|
+
rescue => e
|
627
627
|
close
|
628
|
-
if SSLEnabled and
|
629
|
-
raise KeepAliveDisconnected.new(self,
|
628
|
+
if SSLEnabled and e.is_a?(OpenSSL::SSL::SSLError)
|
629
|
+
raise KeepAliveDisconnected.new(self, e)
|
630
630
|
else
|
631
631
|
raise
|
632
632
|
end
|
@@ -797,13 +797,13 @@ class HTTPClient
|
|
797
797
|
socket = nil
|
798
798
|
begin
|
799
799
|
@debug_dev << "! CONNECT TO #{site.host}:#{site.port}\n" if @debug_dev
|
800
|
-
|
801
|
-
clean_local = @socket_local.host.delete("[]")
|
800
|
+
clean_host = site.host.delete("[]")
|
802
801
|
if str = @test_loopback_http_response.shift
|
803
802
|
socket = LoopBackSocket.new(clean_host, site.port, str)
|
804
803
|
elsif @socket_local == Site::EMPTY
|
805
804
|
socket = TCPSocket.new(clean_host, site.port)
|
806
805
|
else
|
806
|
+
clean_local = @socket_local.host.delete("[]")
|
807
807
|
socket = TCPSocket.new(clean_host, site.port, clean_local, @socket_local.port)
|
808
808
|
end
|
809
809
|
if @debug_dev
|
data/lib/httpclient/version.rb
CHANGED
data/test/test_auth.rb
CHANGED
@@ -141,8 +141,10 @@ class TestAuth < Test::Unit::TestCase
|
|
141
141
|
c = HTTPClient.new
|
142
142
|
webrick_backup = @basic_auth.instance_eval { @auth_scheme }
|
143
143
|
begin
|
144
|
+
# WEBrick in ruby 1.8.7 uses 'BASIC' instead of 'Basic'
|
144
145
|
@basic_auth.instance_eval { @auth_scheme = "BASIC" }
|
145
146
|
c.www_auth.basic_auth.instance_eval { @scheme = "BASIC" }
|
147
|
+
#
|
146
148
|
c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
|
147
149
|
assert_equal('basic_auth OK', c.get_content("http://localhost:#{serverport}/basic_auth"))
|
148
150
|
ensure
|
@@ -150,6 +152,41 @@ class TestAuth < Test::Unit::TestCase
|
|
150
152
|
end
|
151
153
|
end
|
152
154
|
|
155
|
+
def test_BASIC_auth_force
|
156
|
+
c = HTTPClient.new
|
157
|
+
webrick_backup = @basic_auth.instance_eval { @auth_scheme }
|
158
|
+
begin
|
159
|
+
# WEBrick in ruby 1.8.7 uses 'BASIC' instead of 'Basic'
|
160
|
+
@basic_auth.instance_eval { @auth_scheme = "BASIC" }
|
161
|
+
c.www_auth.basic_auth.instance_eval { @scheme = "BASIC" }
|
162
|
+
#
|
163
|
+
c.force_basic_auth = true
|
164
|
+
c.debug_dev = str = ''
|
165
|
+
c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
|
166
|
+
assert_equal('basic_auth OK', c.get_content("http://localhost:#{serverport}/basic_auth"))
|
167
|
+
assert_equal('Authorization: Basic YWRtaW46YWRtaW4='.upcase, str.split(/\r?\n/)[5].upcase)
|
168
|
+
ensure
|
169
|
+
@basic_auth.instance_eval { @auth_scheme = webrick_backup }
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_BASIC_auth_async
|
174
|
+
# async methods don't issure retry call so for successful authentication you need to set force_basic_auth flag
|
175
|
+
c = HTTPClient.new(:force_basic_auth => true)
|
176
|
+
webrick_backup = @basic_auth.instance_eval { @auth_scheme }
|
177
|
+
begin
|
178
|
+
# WEBrick in ruby 1.8.7 uses 'BASIC' instead of 'Basic'
|
179
|
+
@basic_auth.instance_eval { @auth_scheme = "BASIC" }
|
180
|
+
c.www_auth.basic_auth.instance_eval { @scheme = "BASIC" }
|
181
|
+
#
|
182
|
+
c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
|
183
|
+
conn = c.get_async("http://localhost:#{serverport}/basic_auth")
|
184
|
+
assert_equal('basic_auth OK', conn.pop.body.read)
|
185
|
+
ensure
|
186
|
+
@basic_auth.instance_eval { @auth_scheme = webrick_backup }
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
153
190
|
def test_BASIC_auth_nil_uri
|
154
191
|
c = HTTPClient.new
|
155
192
|
webrick_backup = @basic_auth.instance_eval { @auth_scheme }
|
data/test/test_http-access2.rb
CHANGED
@@ -118,8 +118,8 @@ class TestClient < Test::Unit::TestCase
|
|
118
118
|
escape_noproxy do
|
119
119
|
begin
|
120
120
|
@client.proxy = "http://あ"
|
121
|
-
rescue
|
122
|
-
assert_match(/InvalidURIError/,
|
121
|
+
rescue => e
|
122
|
+
assert_match(/InvalidURIError/, e.class.to_s)
|
123
123
|
end
|
124
124
|
@client.proxy = ""
|
125
125
|
assert_nil(@client.proxy)
|
data/test/test_httpclient.rb
CHANGED
@@ -177,8 +177,8 @@ class TestHTTPClient < Test::Unit::TestCase
|
|
177
177
|
escape_noproxy do
|
178
178
|
begin
|
179
179
|
@client.proxy = "http://あ"
|
180
|
-
rescue
|
181
|
-
assert_match(/InvalidURIError/,
|
180
|
+
rescue => e
|
181
|
+
assert_match(/InvalidURIError/, e.class.to_s)
|
182
182
|
end
|
183
183
|
@client.proxy = ""
|
184
184
|
assert_nil(@client.proxy)
|
@@ -554,6 +554,28 @@ EOS
|
|
554
554
|
assert(called)
|
555
555
|
end
|
556
556
|
|
557
|
+
def test_get_content_with_base_url
|
558
|
+
@client = HTTPClient.new(:base_url => serverurl[0..-1])
|
559
|
+
assert_equal('hello', @client.get_content('/hello'))
|
560
|
+
assert_equal('hello', @client.get_content('/redirect1'))
|
561
|
+
assert_equal('hello', @client.get_content('/redirect2'))
|
562
|
+
@client.reset('/')
|
563
|
+
assert_raises(HTTPClient::BadResponseError) do
|
564
|
+
@client.get_content('/notfound')
|
565
|
+
end
|
566
|
+
assert_raises(HTTPClient::BadResponseError) do
|
567
|
+
@client.get_content('/redirect_self')
|
568
|
+
end
|
569
|
+
called = false
|
570
|
+
@client.redirect_uri_callback = lambda { |uri, res|
|
571
|
+
newuri = res.header['location'][0]
|
572
|
+
called = true
|
573
|
+
newuri
|
574
|
+
}
|
575
|
+
assert_equal('hello', @client.get_content('/relative_redirect'))
|
576
|
+
assert(called)
|
577
|
+
end
|
578
|
+
|
557
579
|
GZIP_CONTENT = "\x1f\x8b\x08\x00\x1a\x96\xe0\x4c\x00\x03\xcb\x48\xcd\xc9\xc9\x07\x00\x86\xa6\x10\x36\x05\x00\x00\x00"
|
558
580
|
DEFLATE_CONTENT = "\x78\x9c\xcb\x48\xcd\xc9\xc9\x07\x00\x06\x2c\x02\x15"
|
559
581
|
GZIP_CONTENT.force_encoding('BINARY') if GZIP_CONTENT.respond_to?(:force_encoding)
|
@@ -640,6 +662,21 @@ EOS
|
|
640
662
|
assert_nil(res.contenttype)
|
641
663
|
end
|
642
664
|
|
665
|
+
def test_get_with_base_url
|
666
|
+
@client = HTTPClient.new(:base_url => serverurl[0..-1])
|
667
|
+
assert_equal("get", @client.get('/servlet').content)
|
668
|
+
param = {'1'=>'2', '3'=>'4'}
|
669
|
+
res = @client.get('/servlet', param)
|
670
|
+
assert_equal(param, params(res.header["x-query"][0]))
|
671
|
+
assert_nil(res.contenttype)
|
672
|
+
#
|
673
|
+
@client.base_url = serverurl[0..-1] + '/servlet'
|
674
|
+
url = '?5=6&7=8'
|
675
|
+
res = @client.get(url, param)
|
676
|
+
assert_equal(param.merge("5"=>"6", "7"=>"8"), params(res.header["x-query"][0]))
|
677
|
+
assert_nil(res.contenttype)
|
678
|
+
end
|
679
|
+
|
643
680
|
def test_head_follow_redirect
|
644
681
|
expected = urify(serverurl + 'hello')
|
645
682
|
assert_equal(expected, @client.head(serverurl + 'hello', :follow_redirect => true).header.request_uri)
|
@@ -661,6 +698,22 @@ EOS
|
|
661
698
|
assert_equal(param, params(res.header["x-query"][0]))
|
662
699
|
end
|
663
700
|
|
701
|
+
def test_get_async_with_base_url
|
702
|
+
param = {'1'=>'2', '3'=>'4'}
|
703
|
+
@client = HTTPClient.new(:base_url => serverurl)
|
704
|
+
|
705
|
+
# Use preconfigured :base_url
|
706
|
+
conn = @client.get_async('servlet', param)
|
707
|
+
Thread.pass while !conn.finished?
|
708
|
+
res = conn.pop
|
709
|
+
assert_equal(param, params(res.header["x-query"][0]))
|
710
|
+
# full URL still works
|
711
|
+
conn = @client.get_async(serverurl + 'servlet', param)
|
712
|
+
Thread.pass while !conn.finished?
|
713
|
+
res = conn.pop
|
714
|
+
assert_equal(param, params(res.header["x-query"][0]))
|
715
|
+
end
|
716
|
+
|
664
717
|
def test_get_async_for_largebody
|
665
718
|
conn = @client.get_async(serverurl + 'largebody')
|
666
719
|
res = conn.pop
|
data/test/test_ssl.rb
CHANGED
@@ -230,7 +230,7 @@ private
|
|
230
230
|
|
231
231
|
def setup_server_with_ssl_version(ssl_version)
|
232
232
|
logger = Logger.new(STDERR)
|
233
|
-
|
233
|
+
logger.level = Logger::Severity::FATAL # avoid logging SSLError (ERROR level)
|
234
234
|
@server = WEBrick::HTTPServer.new(
|
235
235
|
:BindAddress => "localhost",
|
236
236
|
:Logger => logger,
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: httpclient
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.5.
|
4
|
+
version: 2.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hiroshi Nakamura
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-10-
|
11
|
+
date: 2014-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email: nahi@ruby-lang.org
|