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.
@@ -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(/=/) ## value may nil
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
@@ -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 = 0
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
- m.header.body_size = m.body.size
649
- m.header.chunked = true if m.body.size.nil?
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
 
@@ -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
- @socket.readpartial(maxbytes, buf) rescue EOFError
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
- @socket.readpartial(@read_block_size, buf) rescue EOFError
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
- file = File.join(File.dirname(__FILE__), 'cacert.p7s')
343
- if File.exist?(file)
344
- dist_cert =<<__DIST_CERT__
345
- -----BEGIN CERTIFICATE-----
346
- MIIC/jCCAmegAwIBAgIBATANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJKUDER
347
- MA8GA1UECgwIY3Rvci5vcmcxFDASBgNVBAsMC0RldmVsb3BtZW50MRUwEwYDVQQD
348
- DAxodHRwLWFjY2VzczIwHhcNMDcwOTExMTM1ODMxWhcNMDkwOTEwMTM1ODMxWjBN
349
- MQswCQYDVQQGEwJKUDERMA8GA1UECgwIY3Rvci5vcmcxFDASBgNVBAsMC0RldmVs
350
- b3BtZW50MRUwEwYDVQQDDAxodHRwLWFjY2VzczIwgZ8wDQYJKoZIhvcNAQEBBQAD
351
- gY0AMIGJAoGBALi66ujWtUCQm5HpMSyr/AAIFYVXC/dmn7C8TR/HMiUuW3waY4uX
352
- LFqCDAGOX4gf177pX+b99t3mpaiAjJuqc858D9xEECzhDWgXdLbhRqWhUOble4RY
353
- c1yWYC990IgXJDMKx7VAuZ3cBhdBxtlE9sb1ZCzmHQsvTy/OoRzcJCrTAgMBAAGj
354
- ge0wgeowDwYDVR0TAQH/BAUwAwEB/zAxBglghkgBhvhCAQ0EJBYiUnVieS9PcGVu
355
- U1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUJNE0GGaRKmN2qhnO
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
 
@@ -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")})
@@ -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[6])
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
@@ -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[6])
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
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-03-27 00:00:00 -07:00
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: 2
84
+ specification_version: 3
84
85
  summary: gives something like the functionality of libwww-perl (LWP) in Ruby
85
86
  test_files: []
86
87