bterlson-httpclient 2.1.4 → 2.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +56 -2
- data/VERSION.yml +1 -1
- data/lib/httpclient.rb +30 -18
- data/lib/httpclient/auth.rb +18 -7
- data/lib/httpclient/cacert.p7s +670 -30
- data/lib/httpclient/cacert_sha1.p7s +1579 -0
- data/lib/httpclient/cookie.rb +3 -1
- data/lib/httpclient/http.rb +8 -4
- data/lib/httpclient/session.rb +12 -4
- data/lib/httpclient/ssl_config.rb +69 -31
- data/test/test_cookie.rb +12 -0
- data/test/test_http-access2.rb +1 -1
- data/test/test_httpclient.rb +84 -1
- metadata +4 -3
data/lib/httpclient/cookie.rb
CHANGED
@@ -160,8 +160,10 @@ class WebAgent
|
|
160
160
|
|
161
161
|
def parse(str, url)
|
162
162
|
@url = url
|
163
|
+
# TODO: should not depend on join_quotedstr. scan with escape like CSV.
|
163
164
|
cookie_elem = str.split(/;/)
|
164
165
|
cookie_elem = join_quotedstr(cookie_elem, ';')
|
166
|
+
cookie_elem -= [""] # del empty elements, a cookie might included ";;"
|
165
167
|
first_elem = cookie_elem.shift
|
166
168
|
if first_elem !~ /([^=]*)(\=(.*))?/
|
167
169
|
return
|
@@ -170,7 +172,7 @@ class WebAgent
|
|
170
172
|
@name = $1.strip
|
171
173
|
@value = normalize_cookie_value($3)
|
172
174
|
cookie_elem.each{|pair|
|
173
|
-
key, value = pair.split(
|
175
|
+
key, value = pair.split(/=/, 2) ## value may nil
|
174
176
|
key.strip!
|
175
177
|
value = normalize_cookie_value(value)
|
176
178
|
case key.downcase
|
data/lib/httpclient/http.rb
CHANGED
@@ -320,7 +320,7 @@ module HTTP
|
|
320
320
|
end
|
321
321
|
if @chunked
|
322
322
|
set('Transfer-Encoding', 'chunked')
|
323
|
-
elsif keep_alive or @body_size != 0
|
323
|
+
elsif @body_size and (keep_alive or @body_size != 0)
|
324
324
|
set('Content-Length', @body_size.to_s)
|
325
325
|
end
|
326
326
|
if @http_version >= 1.1
|
@@ -623,7 +623,7 @@ module HTTP
|
|
623
623
|
def new_connect_request(uri)
|
624
624
|
m = new
|
625
625
|
m.header.init_connect_request(uri)
|
626
|
-
m.header.body_size =
|
626
|
+
m.header.body_size = nil
|
627
627
|
m
|
628
628
|
end
|
629
629
|
|
@@ -645,8 +645,12 @@ module HTTP
|
|
645
645
|
m.header.init_request(method, uri, query)
|
646
646
|
m.body = Body.new
|
647
647
|
m.body.init_request(body || '', boundary)
|
648
|
-
|
649
|
-
|
648
|
+
if body
|
649
|
+
m.header.body_size = m.body.size
|
650
|
+
m.header.chunked = true if m.body.size.nil?
|
651
|
+
else
|
652
|
+
m.header.body_size = nil
|
653
|
+
end
|
650
654
|
m
|
651
655
|
end
|
652
656
|
|
data/lib/httpclient/session.rb
CHANGED
@@ -445,7 +445,7 @@ class HTTPClient
|
|
445
445
|
include SocketWrap
|
446
446
|
|
447
447
|
def initialize(host, port, response)
|
448
|
-
super(StringIO.new(response))
|
448
|
+
super(response.is_a?(StringIO) ? response : StringIO.new(response))
|
449
449
|
@host = host
|
450
450
|
@port = port
|
451
451
|
end
|
@@ -800,9 +800,13 @@ class HTTPClient
|
|
800
800
|
maxbytes = @read_block_size
|
801
801
|
maxbytes = @content_length if maxbytes > @content_length
|
802
802
|
timeout(@receive_timeout, ReceiveTimeoutError) do
|
803
|
-
|
803
|
+
begin
|
804
|
+
@socket.readpartial(maxbytes, buf)
|
805
|
+
rescue EOFError
|
806
|
+
buf = nil
|
807
|
+
end
|
804
808
|
end
|
805
|
-
if buf.length > 0
|
809
|
+
if buf && buf.length > 0
|
806
810
|
@content_length -= buf.length
|
807
811
|
yield buf
|
808
812
|
else
|
@@ -840,7 +844,11 @@ class HTTPClient
|
|
840
844
|
buf = ''
|
841
845
|
while true
|
842
846
|
timeout(@receive_timeout, ReceiveTimeoutError) do
|
843
|
-
|
847
|
+
begin
|
848
|
+
@socket.readpartial(@read_block_size, buf)
|
849
|
+
rescue EOFError
|
850
|
+
buf = nil
|
851
|
+
end
|
844
852
|
end
|
845
853
|
if buf && buf.length > 0
|
846
854
|
yield buf
|
@@ -339,40 +339,78 @@ class HTTPClient
|
|
339
339
|
end
|
340
340
|
|
341
341
|
def load_cacerts
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
FyBWVl4Qj6owDgYDVR0PAQH/BAQDAgEGMHUGA1UdIwRuMGyAFCTRNBhmkSpjdqoZ
|
357
|
-
zhcgVlZeEI+qoVGkTzBNMQswCQYDVQQGEwJKUDERMA8GA1UECgwIY3Rvci5vcmcx
|
358
|
-
FDASBgNVBAsMC0RldmVsb3BtZW50MRUwEwYDVQQDDAxodHRwLWFjY2VzczKCAQEw
|
359
|
-
DQYJKoZIhvcNAQEFBQADgYEAH11tstSUuqFpMqoh/vM5l3Nqb8ygblbqEYQs/iG/
|
360
|
-
UeQkOZk/P1TxB6Ozn2htJ1srqDpUsncFVZ/ecP19GkeOZ6BmIhppcHhE5WyLBcPX
|
361
|
-
It5q1BW0PiAzT9LlEGoaiW0nw39so0Pr1whJDfc1t4fjdk+kSiMIzRHbTDvHWfpV
|
362
|
-
nTA=
|
363
|
-
-----END CERTIFICATE-----
|
364
|
-
__DIST_CERT__
|
365
|
-
p7 = PKCS7.read_smime(File.open(file) { |f| f.read })
|
366
|
-
selfcert = X509::Certificate.new(dist_cert)
|
367
|
-
store = X509::Store.new
|
368
|
-
store.add_cert(selfcert)
|
369
|
-
if (p7.verify(nil, store, p7.data, 0))
|
370
|
-
set_trust_ca(file)
|
371
|
-
else
|
372
|
-
STDERR.puts("cacerts: #{file} loading failed")
|
342
|
+
[
|
343
|
+
[DIST_CERT, 'cacert.p7s'],
|
344
|
+
[DIST_CERT_SHA1, 'cacert_sha1.p7s']
|
345
|
+
].each do |cert_str, ca_file|
|
346
|
+
file = File.join(File.dirname(__FILE__), ca_file)
|
347
|
+
if File.exist?(file)
|
348
|
+
p7 = PKCS7.read_smime(File.open(file) { |f| f.read })
|
349
|
+
selfcert = X509::Certificate.new(cert_str)
|
350
|
+
store = X509::Store.new
|
351
|
+
store.add_cert(selfcert)
|
352
|
+
if (p7.verify(nil, store, p7.data, 0))
|
353
|
+
set_trust_ca(file)
|
354
|
+
return
|
355
|
+
end
|
373
356
|
end
|
374
357
|
end
|
358
|
+
STDERR.puts("cacerts loading failed")
|
375
359
|
end
|
360
|
+
|
361
|
+
DIST_CERT =<<__DIST_CERT__
|
362
|
+
-----BEGIN CERTIFICATE-----
|
363
|
+
MIID/TCCAuWgAwIBAgIBATANBgkqhkiG9w0BAQ0FADBLMQswCQYDVQQGEwJKUDER
|
364
|
+
MA8GA1UECgwIY3Rvci5vcmcxFDASBgNVBAsMC0RldmVsb3BtZW50MRMwEQYDVQQD
|
365
|
+
DApodHRwY2xpZW50MB4XDTA5MDUyMTEyMzkwNVoXDTM3MTIzMTIzNTk1OVowSzEL
|
366
|
+
MAkGA1UEBhMCSlAxETAPBgNVBAoMCGN0b3Iub3JnMRQwEgYDVQQLDAtEZXZlbG9w
|
367
|
+
bWVudDETMBEGA1UEAwwKaHR0cGNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
368
|
+
ADCCAQoCggEBAM2PlkdTH97zvIHoPIMj87wnNvpqIQUD7L/hlysO0XBsmR/XZUeU
|
369
|
+
ZKB10JQqMXviWpTnU9KU6xGTx3EI4wfd2dpLwH/d4d7K4LngW1kY7kJlZeJhakno
|
370
|
+
GzQ40RSI9WkQ0R9KOE888f7OkTBafcL8UyWFVIMhQBw2d9iNl4Jc69QojayCDoSX
|
371
|
+
XbbEP0n8yi7HwIU3RFuX6DtMpOx4/1K7Z002ccOGJ3J9kHgeDQSQtF42cQYC7qj2
|
372
|
+
67I/OQgnB7ycxTCP0E7bdXQg+zqsngrhaoNn/+I+CoO7nD4t4uQ+B4agALh4PPxs
|
373
|
+
bQD9MCL+VurNGLYv0HVd+ZlLblpddC9PLTsCAwEAAaOB6zCB6DAPBgNVHRMBAf8E
|
374
|
+
BTADAQH/MDEGCWCGSAGG+EIBDQQkFiJSdWJ5L09wZW5TU0wgR2VuZXJhdGVkIENl
|
375
|
+
cnRpZmljYXRlMB0GA1UdDgQWBBRAnB6XlMoOcm7HVAw+JWxY205PHTAOBgNVHQ8B
|
376
|
+
Af8EBAMCAQYwcwYDVR0jBGwwaoAUQJwel5TKDnJux1QMPiVsWNtOTx2hT6RNMEsx
|
377
|
+
CzAJBgNVBAYTAkpQMREwDwYDVQQKDAhjdG9yLm9yZzEUMBIGA1UECwwLRGV2ZWxv
|
378
|
+
cG1lbnQxEzARBgNVBAMMCmh0dHBjbGllbnSCAQEwDQYJKoZIhvcNAQENBQADggEB
|
379
|
+
ABVFepybD5XqsBnOn/oDHvK0xAPMF4Ap4Ht1yMQLObg8paVhANSdqIevPlCr/mPL
|
380
|
+
DRjcy+J1fCnE6lCfsfLdTgAjirqt8pm92NccxmJ8hTmMd3LWC1n+eYWaolqTCVRM
|
381
|
+
Bpe8UY9enyXrFoudHlr9epr18E6As6VrCSfpXFZkD9WHVSWpzkB3qATu5qcDCzCH
|
382
|
+
bI0755Mdm/1hKJCD4l69h3J3OhRIEUPJfHnPvM5wtiyC2dcE9itwE/wdVzBJeIBX
|
383
|
+
JQm+Qj+K8qXcRTzZZGIBjw2n46xJgW6YncNCHU/WWfNCYwdkngHS/aN8IbEjhCwf
|
384
|
+
viXFisVrDN/+pZZGMf67ZaY=
|
385
|
+
-----END CERTIFICATE-----
|
386
|
+
__DIST_CERT__
|
387
|
+
|
388
|
+
DIST_CERT_SHA1 =<<__DIST_CERT__
|
389
|
+
-----BEGIN CERTIFICATE-----
|
390
|
+
MIID/TCCAuWgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJKUDER
|
391
|
+
MA8GA1UECgwIY3Rvci5vcmcxFDASBgNVBAsMC0RldmVsb3BtZW50MRMwEQYDVQQD
|
392
|
+
DApodHRwY2xpZW50MB4XDTA5MDYyNTE0MjUzN1oXDTEwMTIzMTIzNTk1OVowSzEL
|
393
|
+
MAkGA1UEBhMCSlAxETAPBgNVBAoMCGN0b3Iub3JnMRQwEgYDVQQLDAtEZXZlbG9w
|
394
|
+
bWVudDETMBEGA1UEAwwKaHR0cGNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
395
|
+
ADCCAQoCggEBAM2PlkdTH97zvIHoPIMj87wnNvpqIQUD7L/hlysO0XBsmR/XZUeU
|
396
|
+
ZKB10JQqMXviWpTnU9KU6xGTx3EI4wfd2dpLwH/d4d7K4LngW1kY7kJlZeJhakno
|
397
|
+
GzQ40RSI9WkQ0R9KOE888f7OkTBafcL8UyWFVIMhQBw2d9iNl4Jc69QojayCDoSX
|
398
|
+
XbbEP0n8yi7HwIU3RFuX6DtMpOx4/1K7Z002ccOGJ3J9kHgeDQSQtF42cQYC7qj2
|
399
|
+
67I/OQgnB7ycxTCP0E7bdXQg+zqsngrhaoNn/+I+CoO7nD4t4uQ+B4agALh4PPxs
|
400
|
+
bQD9MCL+VurNGLYv0HVd+ZlLblpddC9PLTsCAwEAAaOB6zCB6DAPBgNVHRMBAf8E
|
401
|
+
BTADAQH/MDEGCWCGSAGG+EIBDQQkFiJSdWJ5L09wZW5TU0wgR2VuZXJhdGVkIENl
|
402
|
+
cnRpZmljYXRlMB0GA1UdDgQWBBRAnB6XlMoOcm7HVAw+JWxY205PHTAOBgNVHQ8B
|
403
|
+
Af8EBAMCAQYwcwYDVR0jBGwwaoAUQJwel5TKDnJux1QMPiVsWNtOTx2hT6RNMEsx
|
404
|
+
CzAJBgNVBAYTAkpQMREwDwYDVQQKDAhjdG9yLm9yZzEUMBIGA1UECwwLRGV2ZWxv
|
405
|
+
cG1lbnQxEzARBgNVBAMMCmh0dHBjbGllbnSCAQIwDQYJKoZIhvcNAQEFBQADggEB
|
406
|
+
AGKhgByl/ur6SBFFKJcISJONFRaxf2ji0l6ut9XO1H2BSOSRjUbsFDWdWZG+D24Q
|
407
|
+
JKKseSWPWAC5uHq00sBWkvmtip+duESPeDEdumdBhdiUUgGamW2Ew2y4yAdAVDeG
|
408
|
+
t1p2fs8SylQN6AMTG/+R+MGHxhvg+UELYLcvAjjcDW2VhDQaJ1eFEfcMW1zRtvvh
|
409
|
+
LJmVErouwFKyAjwhbF6sNxmToSnbO1ciWwIILMsOBNHMETCp+SzkRDIRWIkm6m+q
|
410
|
+
RwRyYoHysODGvnu8VXS1hGRr2GIxeBga7dAGa2VLE/iUQ0d4lEskYU+6C4ZLyAWF
|
411
|
+
O89dvLNRzpL10MaWCYVREks=
|
412
|
+
-----END CERTIFICATE-----
|
413
|
+
__DIST_CERT__
|
376
414
|
end
|
377
415
|
|
378
416
|
|
data/test/test_cookie.rb
CHANGED
@@ -168,6 +168,18 @@ class TestCookieManager < Test::Unit::TestCase
|
|
168
168
|
assert_equal(Time.gm(2009,12,31,12,0,0), cookie.expires)
|
169
169
|
end
|
170
170
|
|
171
|
+
def test_parse_double_semicolon()
|
172
|
+
str = "xmen=off,0,0,1;; path=\"/;;\"; domain=.excite.co.jp; expires=Wednesday, 31-Dec-2009 12:00:00 GMT"
|
173
|
+
@cm.parse(str,URI.parse('http://www.excite.co.jp'))
|
174
|
+
cookie = @cm.cookies[0]
|
175
|
+
assert_instance_of(WebAgent::Cookie, cookie)
|
176
|
+
assert_equal("xmen", cookie.name)
|
177
|
+
assert_equal("off,0,0,1", cookie.value)
|
178
|
+
assert_equal("/;;", cookie.path)
|
179
|
+
assert_equal(".excite.co.jp", cookie.domain)
|
180
|
+
assert_equal(Time.gm(2009,12,31,12,0,0), cookie.expires)
|
181
|
+
end
|
182
|
+
|
171
183
|
# def test_make_portlist()
|
172
184
|
# assert_equal([80,8080], @cm.instance_eval{make_portlist("80,8080")})
|
173
185
|
# assert_equal([80], @cm.instance_eval{make_portlist("80")})
|
data/test/test_http-access2.rb
CHANGED
@@ -109,7 +109,7 @@ class TestClient < Test::Unit::TestCase
|
|
109
109
|
assert_equal("= Request", lines[0])
|
110
110
|
assert_equal("! CONNECTION ESTABLISHED", lines[2])
|
111
111
|
assert_equal("GET / HTTP/1.1", lines[3])
|
112
|
-
assert_equal("Host: localhost:#{Port}", lines[
|
112
|
+
assert_equal("Host: localhost:#{Port}", lines[5])
|
113
113
|
@client.protocol_version = 'HTTP/1.1'
|
114
114
|
str = ""
|
115
115
|
@client.debug_dev = str
|
data/test/test_httpclient.rb
CHANGED
@@ -123,7 +123,7 @@ class TestHTTPClient < Test::Unit::TestCase
|
|
123
123
|
assert_equal("= Request", lines[0])
|
124
124
|
assert_equal("! CONNECTION ESTABLISHED", lines[2])
|
125
125
|
assert_equal("GET / HTTP/1.1", lines[3])
|
126
|
-
assert_equal("Host: localhost:#{Port}", lines[
|
126
|
+
assert_equal("Host: localhost:#{Port}", lines[5])
|
127
127
|
@client.protocol_version = 'HTTP/1.1'
|
128
128
|
assert_equal('HTTP/1.1', @client.protocol_version)
|
129
129
|
str = ""
|
@@ -262,6 +262,33 @@ class TestHTTPClient < Test::Unit::TestCase
|
|
262
262
|
end
|
263
263
|
end
|
264
264
|
|
265
|
+
def test_cookie_update_while_authentication
|
266
|
+
escape_noproxy do
|
267
|
+
@client.test_loopback_http_response << <<EOS
|
268
|
+
HTTP/1.0 401\r
|
269
|
+
Date: Fri, 19 Dec 2008 11:57:29 GMT\r
|
270
|
+
Content-Type: text/plain\r
|
271
|
+
Content-Length: 0\r
|
272
|
+
WWW-Authenticate: Basic realm="hello"\r
|
273
|
+
Set-Cookie: foo=bar; path=/; domain=.example.org; expires=#{Time.mktime(2030, 12, 31).httpdate}\r
|
274
|
+
\r
|
275
|
+
EOS
|
276
|
+
@client.test_loopback_http_response << <<EOS
|
277
|
+
HTTP/1.1 200 OK\r
|
278
|
+
Content-Length: 5\r
|
279
|
+
Connection: close\r
|
280
|
+
\r
|
281
|
+
hello
|
282
|
+
EOS
|
283
|
+
@client.debug_dev = str = ''
|
284
|
+
@client.set_auth("http://www.example.org/baz/", 'admin', 'admin')
|
285
|
+
assert_equal('hello', @client.get('http://www.example.org/baz/foo').content)
|
286
|
+
assert_match(/^Cookie: foo=bar/, str)
|
287
|
+
assert_match(/^Authorization: Basic YWRtaW46YWRtaW4=/, str)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
|
265
292
|
def test_proxy_ssl
|
266
293
|
escape_noproxy do
|
267
294
|
@client.proxy = 'http://admin:admin@localhost:8080/'
|
@@ -770,6 +797,62 @@ EOS
|
|
770
797
|
assert_match(%r(http://rubyforge.org/account/login.php foo bar 1924873200 rubyforge.org /login.php 1), str)
|
771
798
|
end
|
772
799
|
|
800
|
+
def test_eof_error_length
|
801
|
+
io = StringIO.new('')
|
802
|
+
def io.gets(*arg)
|
803
|
+
@buf ||= ["HTTP/1.0 200 OK\n", "content-length: 123\n", "\n"]
|
804
|
+
@buf.shift
|
805
|
+
end
|
806
|
+
def io.readpartial(size, buf)
|
807
|
+
@second ||= false
|
808
|
+
if !@second
|
809
|
+
@second = '1st'
|
810
|
+
buf << "abc"
|
811
|
+
buf
|
812
|
+
elsif @second == '1st'
|
813
|
+
@second = '2nd'
|
814
|
+
raise EOFError.new
|
815
|
+
else
|
816
|
+
raise Exception.new
|
817
|
+
end
|
818
|
+
end
|
819
|
+
def io.eof?
|
820
|
+
true
|
821
|
+
end
|
822
|
+
@client.test_loopback_http_response << io
|
823
|
+
assert_nothing_raised do
|
824
|
+
@client.get('http://foo/bar')
|
825
|
+
end
|
826
|
+
end
|
827
|
+
|
828
|
+
def test_eof_error_rest
|
829
|
+
io = StringIO.new('')
|
830
|
+
def io.gets(*arg)
|
831
|
+
@buf ||= ["HTTP/1.0 200 OK\n", "\n"]
|
832
|
+
@buf.shift
|
833
|
+
end
|
834
|
+
def io.readpartial(size, buf)
|
835
|
+
@second ||= false
|
836
|
+
if !@second
|
837
|
+
@second = '1st'
|
838
|
+
buf << "abc"
|
839
|
+
buf
|
840
|
+
elsif @second == '1st'
|
841
|
+
@second = '2nd'
|
842
|
+
raise EOFError.new
|
843
|
+
else
|
844
|
+
raise Exception.new
|
845
|
+
end
|
846
|
+
end
|
847
|
+
def io.eof?
|
848
|
+
true
|
849
|
+
end
|
850
|
+
@client.test_loopback_http_response << io
|
851
|
+
assert_nothing_raised do
|
852
|
+
@client.get('http://foo/bar')
|
853
|
+
end
|
854
|
+
end
|
855
|
+
|
773
856
|
def test_urify
|
774
857
|
extend HTTPClient::Util
|
775
858
|
assert_nil(urify(nil))
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bterlson-httpclient
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- NAKAMURA, Hiroshi
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-
|
13
|
+
date: 2009-07-02 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -32,6 +32,7 @@ files:
|
|
32
32
|
- lib/httpclient
|
33
33
|
- lib/httpclient/auth.rb
|
34
34
|
- lib/httpclient/cacert.p7s
|
35
|
+
- lib/httpclient/cacert_sha1.p7s
|
35
36
|
- lib/httpclient/connection.rb
|
36
37
|
- lib/httpclient/cookie.rb
|
37
38
|
- lib/httpclient/http.rb
|
@@ -80,7 +81,7 @@ requirements: []
|
|
80
81
|
rubyforge_project:
|
81
82
|
rubygems_version: 1.2.0
|
82
83
|
signing_key:
|
83
|
-
specification_version:
|
84
|
+
specification_version: 3
|
84
85
|
summary: gives something like the functionality of libwww-perl (LWP) in Ruby
|
85
86
|
test_files: []
|
86
87
|
|