httpclient 2.2.0.2 → 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/lib/httpclient.rb +5 -5
  2. data/lib/httpclient/cacert.p7s +12 -12
  3. data/lib/httpclient/cacert_sha1.p7s +12 -12
  4. data/lib/httpclient/http.rb +15 -8
  5. data/lib/httpclient/session.rb +6 -1
  6. data/lib/httpclient/ssl_config.rb +18 -14
  7. data/sample/async.rb +8 -0
  8. data/sample/auth.rb +11 -0
  9. data/sample/cookie.rb +18 -0
  10. data/sample/dav.rb +103 -0
  11. data/sample/howto.rb +49 -0
  12. data/sample/oauth_buzz.rb +57 -0
  13. data/sample/oauth_friendfeed.rb +59 -0
  14. data/sample/oauth_twitter.rb +61 -0
  15. data/sample/ssl/0cert.pem +22 -0
  16. data/sample/ssl/0key.pem +30 -0
  17. data/sample/ssl/1000cert.pem +19 -0
  18. data/sample/ssl/1000key.pem +18 -0
  19. data/sample/ssl/htdocs/index.html +10 -0
  20. data/sample/ssl/ssl_client.rb +22 -0
  21. data/sample/ssl/webrick_httpsd.rb +29 -0
  22. data/sample/stream.rb +21 -0
  23. data/sample/thread.rb +27 -0
  24. data/sample/wcat.rb +21 -0
  25. data/test/ca.cert +23 -0
  26. data/test/client.cert +19 -0
  27. data/test/client.key +15 -0
  28. data/test/helper.rb +99 -0
  29. data/test/htdigest +1 -0
  30. data/test/htpasswd +2 -0
  31. data/test/runner.rb +2 -0
  32. data/test/server.cert +19 -0
  33. data/test/server.key +15 -0
  34. data/test/sslsvr.rb +65 -0
  35. data/test/subca.cert +21 -0
  36. data/test/test_auth.rb +196 -0
  37. data/test/test_cookie.rb +398 -0
  38. data/test/test_http-access2.rb +497 -0
  39. data/test/test_httpclient.rb +1544 -0
  40. data/test/test_ssl.rb +215 -0
  41. metadata +53 -38
  42. data/lib/http-access2.rbc +0 -732
  43. data/lib/httpclient.rbc +0 -13559
  44. data/lib/httpclient/auth.rbc +0 -13772
  45. data/lib/httpclient/connection.rbc +0 -767
  46. data/lib/httpclient/cookie.rbc +0 -8442
  47. data/lib/httpclient/http.rbc +0 -14163
  48. data/lib/httpclient/session.rbc +0 -15846
  49. data/lib/httpclient/ssl_config.rbc +0 -5575
  50. data/lib/httpclient/timeout.rbc +0 -2411
  51. data/lib/httpclient/util.rbc +0 -1278
@@ -229,7 +229,7 @@ require 'httpclient/cookie'
229
229
  # ruby -rhttpclient -e 'p HTTPClient.head(ARGV.shift).header["last-modified"]' http://dev.ctor.org/
230
230
  #
231
231
  class HTTPClient
232
- VERSION = '2.2.0.2'
232
+ VERSION = '2.2.1'
233
233
  RUBY_VERSION_STRING = "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
234
234
  /: (\S+) (\S+)/ =~ %q$Id$
235
235
  LIB_NAME = "(#{$1}/#{$2}, #{RUBY_VERSION_STRING})"
@@ -438,7 +438,7 @@ class HTTPClient
438
438
  #
439
439
  # Calling this method resets all existing sessions.
440
440
  def proxy=(proxy)
441
- if proxy.nil?
441
+ if proxy.nil? || proxy.to_s.empty?
442
442
  @proxy = nil
443
443
  @proxy_auth.reset_challenge
444
444
  else
@@ -728,9 +728,9 @@ class HTTPClient
728
728
  # a HTTP request message body.
729
729
  #
730
730
  # When you pass an IO as a body, HTTPClient sends it as a HTTP request with
731
- # chunked encoding (Transfer-Encoding: chunked in HTTP header). Bear in mind
732
- # that some server application does not support chunked request. At least
733
- # cgi.rb does not support it.
731
+ # chunked encoding (Transfer-Encoding: chunked in HTTP header) if IO does not
732
+ # respond to :read. Bear in mind that some server application does not support
733
+ # chunked request. At least cgi.rb does not support it.
734
734
  def request(method, uri, *args, &block)
735
735
  query, body, header, follow_redirect = keyword_argument(args, :query, :body, :header, :follow_redirect)
736
736
  if [:post, :put].include?(method)
@@ -1,9 +1,9 @@
1
1
  MIME-Version: 1.0
2
- Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg="sha1"; boundary="----FD1775D1D9127483D5635511E610AF67"
2
+ Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg="sha1"; boundary="----FC1E47CA462F4279D20B7F02AEA7E734"
3
3
 
4
4
  This is an S/MIME signed message
5
5
 
6
- ------FD1775D1D9127483D5635511E610AF67
6
+ ------FC1E47CA462F4279D20B7F02AEA7E734
7
7
  -----BEGIN CERTIFICATE-----
8
8
  MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU
9
9
  MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
@@ -1813,7 +1813,7 @@ lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3
1813
1813
  7M2CYfE45k+XmCpajQ==
1814
1814
  -----END CERTIFICATE-----
1815
1815
 
1816
- ------FD1775D1D9127483D5635511E610AF67
1816
+ ------FC1E47CA462F4279D20B7F02AEA7E734
1817
1817
  Content-Type: application/pkcs7-signature; name="smime.p7s"
1818
1818
  Content-Transfer-Encoding: base64
1819
1819
  Content-Disposition: attachment; filename="smime.p7s"
@@ -1843,16 +1843,16 @@ BO7mpwMLMIdsjTvnkx2b/WEokIPiXr2Hcnc6FEgRQ8l8ec+8znC2LILZ1wT2K3AT
1843
1843
  o3whsSOELB++JcWKxWsM3/6llkYx/rtlpjGCAiswggInAgEBMFAwSzELMAkGA1UE
1844
1844
  BhMCSlAxETAPBgNVBAoMCGN0b3Iub3JnMRQwEgYDVQQLDAtEZXZlbG9wbWVudDET
1845
1845
  MBEGA1UEAwwKaHR0cGNsaWVudAIBATAJBgUrDgMCGgUAoIGxMBgGCSqGSIb3DQEJ
1846
- AzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTExMDQxOTEzMTk1MFowIwYJ
1846
+ AzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTExMDUyMjA4NTEyMFowIwYJ
1847
1847
  KoZIhvcNAQkEMRYEFB6px2QzZcvvEHTjt2rAmZJQzfDEMFIGCSqGSIb3DQEJDzFF
1848
1848
  MEMwCgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcG
1849
- BSsOAwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAD4EMqXaqm6w
1850
- loVOMuk2Etbhp9jBFykE3fOB5WUTTkEH9sgI04Ajoc6CBjud97ngG+WVfK9JK1zG
1851
- D5uEI+8IV5l4N38kzV/CJ3oomMtXlwPvzXYXcHeN3FAPcNwHxKSswMEOyCmn1Xh7
1852
- 3UBvJBiMuqZfCuM63n0ozj5fiYCBUUnhX3fb2pcmswhO8PDEuA2XoYS5sLAmqA20
1853
- 4mklFS4ejN1dmWcJY+cHaS45+pYfzFXtZDaOR7WU+vYIydMoTxBOgVbrjnlciZc0
1854
- eomLCA65FMf8adnS658gfqzstjp7Sq81G7uniUQdipK4BA6uU+Qeg0LRbMSaV4VG
1855
- 8ML4DnOTXME=
1849
+ BSsOAwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAL1U0w4bM8Qr
1850
+ qYow95JP8oCG/ObfF6vFgo3h50kC/iXuKz9092VcUxleieiRHNf4fdv0snWmZD6H
1851
+ aOdxaKaJYdx0ZX6nEnPIYpIZ7w7M3RQhd/BLajIHft4sl0MG5AoDBhp1xLicuHUA
1852
+ EN0a0Zcv2cqHAxu/EiaVfNHyNL1lWPu0MlpNEOh6tBc9kjKplhaZgX7yqzkGXiJj
1853
+ pTyyJ2W+iUUyD4qH2bLGVjXeruK8SKmbsOsS/EbDH/pibY7GyY+UlMyeNo9LmVcH
1854
+ hX93iPwUHfNQLfUDrjVcdx7okIQvSJrg9X3brv4NccRFa/PtqH9RkG5tFH3xnoQq
1855
+ /Q1ATdBt6C4=
1856
1856
 
1857
- ------FD1775D1D9127483D5635511E610AF67--
1857
+ ------FC1E47CA462F4279D20B7F02AEA7E734--
1858
1858
 
@@ -1,9 +1,9 @@
1
1
  MIME-Version: 1.0
2
- Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg="sha1"; boundary="----A7A3ED9F71494B934F978FF49CCFDAA8"
2
+ Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg="sha1"; boundary="----C57026F268CF9C1DB42129AC956CD0BC"
3
3
 
4
4
  This is an S/MIME signed message
5
5
 
6
- ------A7A3ED9F71494B934F978FF49CCFDAA8
6
+ ------C57026F268CF9C1DB42129AC956CD0BC
7
7
  -----BEGIN CERTIFICATE-----
8
8
  MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU
9
9
  MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
@@ -1813,7 +1813,7 @@ lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3
1813
1813
  7M2CYfE45k+XmCpajQ==
1814
1814
  -----END CERTIFICATE-----
1815
1815
 
1816
- ------A7A3ED9F71494B934F978FF49CCFDAA8
1816
+ ------C57026F268CF9C1DB42129AC956CD0BC
1817
1817
  Content-Type: application/pkcs7-signature; name="smime.p7s"
1818
1818
  Content-Transfer-Encoding: base64
1819
1819
  Content-Disposition: attachment; filename="smime.p7s"
@@ -1843,16 +1843,16 @@ YMEtiMT3acFCZEjamCfXIcfLu6Jr7dYc6bvZqLd8tKkKFy01dOSEXIgHtDsthHbv
1843
1843
  t9v4ZZy8AJlYcuqOLLbIs9nL0lnCcKLjITGCAiswggInAgEBMFAwSzELMAkGA1UE
1844
1844
  BhMCSlAxETAPBgNVBAoMCGN0b3Iub3JnMRQwEgYDVQQLDAtEZXZlbG9wbWVudDET
1845
1845
  MBEGA1UEAwwKaHR0cGNsaWVudAIBAjAJBgUrDgMCGgUAoIGxMBgGCSqGSIb3DQEJ
1846
- AzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTExMDQxOTEzMjAwNFowIwYJ
1846
+ AzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTExMDUyMjA4NTE0M1owIwYJ
1847
1847
  KoZIhvcNAQkEMRYEFB6px2QzZcvvEHTjt2rAmZJQzfDEMFIGCSqGSIb3DQEJDzFF
1848
1848
  MEMwCgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcG
1849
- BSsOAwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBACVjHueimi/s
1850
- rHZxaiZMz45S2uXLynpAco67tGw/iguWTk3hKHQ3Dwp2iFmqIYaAPjNeYt/eV7qr
1851
- A+3DVL64tTxSvnNU/lgFOTmq1p8jITrKwdVYBvwWaSNURvTy3bpt3W962hdfmqAL
1852
- CXOdo7h7nXL5haHLFPPw4Hca9Z9mFpM6x1fIjSk/zSRo2W1RgXxva/4F2LKHREcD
1853
- OPfDbTN517z7u+mQ/J7D+4JU8zLQZA8khM0JF/PhuKzy2PxPqrEREZcx+EFy3JHA
1854
- Q6Fdof6LYHrDEZppOrEtJB7UVhoQ1Ksw25T9dMjB2PqLK3hafUtC10iOAQxIfEDH
1855
- ANx4tC98GH8=
1849
+ BSsOAwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAEFfFngL8sd6
1850
+ +P5CqVUuK7XCov5ALywlJJiDnk8LWaFmoM8oQldYOgUE7+Incryzku2XQXQqVXVM
1851
+ TAXSOOsvoJTCHeNopBpJzUEImrm3Cwc7gSS4Zss9l7JtrI+vnWm1DUbmicWkUB+1
1852
+ UDkIGLhRpTdlzIoa/aJi2Di2BMfQ374ej//nYQIOc4GsyDmRyR+Q07P2DLTkQfTF
1853
+ 1F88F+mduib+pz3+BsqGLERONSZOEfiNOZFTfNlc77EzgUk/XcXfFohCVSXXjNRJ
1854
+ oPM4EGs9fZpt8t3f8NG4qiGb6HM/mt1FQhjUrlzXh8VHKW7zYWFSS64I2lml4x82
1855
+ xlt2BAWZwnE=
1856
1856
 
1857
- ------A7A3ED9F71494B934F978FF49CCFDAA8--
1857
+ ------C57026F268CF9C1DB42129AC956CD0BC--
1858
1858
 
@@ -442,18 +442,18 @@ module HTTP
442
442
  def dump(header = '', dev = '')
443
443
  if @body.is_a?(Parts)
444
444
  dev << header
445
- buf = ''
446
445
  @body.parts.each do |part|
447
446
  if Message.file?(part)
448
447
  reset_pos(part)
449
- while !part.read(@chunk_size, buf).nil?
450
- dev << buf
451
- end
452
- part.rewind
448
+ dump_file(part, dev)
453
449
  else
454
450
  dev << part
455
451
  end
456
452
  end
453
+ elsif Message.file?(@body)
454
+ dev << header
455
+ reset_pos(@body)
456
+ dump_file(@body, dev)
457
457
  elsif @body
458
458
  dev << header + @body
459
459
  else
@@ -498,11 +498,11 @@ module HTTP
498
498
 
499
499
  def set_content(body, boundary = nil)
500
500
  if body.respond_to?(:read)
501
- # uses Transfer-Encoding: chunked. bear in mind that server may not
502
- # support it. at least ruby's CGI doesn't.
501
+ # uses Transfer-Encoding: chunked if body does not respond to :size.
502
+ # bear in mind that server may not support it. at least ruby's CGI doesn't.
503
503
  @body = body
504
504
  remember_pos(@body)
505
- @size = nil
505
+ @size = body.respond_to?(:size) ? body.size - body.pos : nil
506
506
  elsif boundary and Message.multiparam_query?(body)
507
507
  @body = build_query_multipart_str(body, boundary)
508
508
  @size = @body.size
@@ -521,6 +521,13 @@ module HTTP
521
521
  io.pos = @positions[io] if @positions.key?(io)
522
522
  end
523
523
 
524
+ def dump_file(io, dev)
525
+ buf = ''
526
+ while !io.read(@chunk_size, buf).nil?
527
+ dev << buf
528
+ end
529
+ end
530
+
524
531
  def dump_chunks(io, dev)
525
532
  buf = ''
526
533
  while !io.read(@chunk_size, buf).nil?
@@ -124,7 +124,7 @@ class HTTPClient
124
124
  @protocol_version = nil
125
125
  @debug_dev = client.debug_dev
126
126
  @socket_sync = true
127
- @chunk_size = 4096
127
+ @chunk_size = ::HTTP::Message::Body::DEFAULT_CHUNK_SIZE
128
128
 
129
129
  @connect_timeout = 60
130
130
  @connect_retry = 1
@@ -899,6 +899,7 @@ class HTTPClient
899
899
  begin
900
900
  @socket.readpartial(maxbytes, buf)
901
901
  rescue EOFError
902
+ close
902
903
  buf = nil
903
904
  end
904
905
  end
@@ -917,6 +918,10 @@ class HTTPClient
917
918
  buf = ''
918
919
  while true
919
920
  len = @socket.gets(RS)
921
+ if len.nil? # EOF
922
+ close
923
+ return
924
+ end
920
925
  @chunk_length = len.hex
921
926
  if @chunk_length == 0
922
927
  @content_length = 0
@@ -146,19 +146,23 @@ class HTTPClient
146
146
  # Calling this method resets all existing sessions.
147
147
  def add_trust_ca(trust_ca_file_or_hashed_dir)
148
148
  @cacerts_loaded = true # avoid lazy override
149
+ add_trust_ca_to_store(@cert_store, trust_ca_file_or_hashed_dir)
150
+ change_notify
151
+ end
152
+ alias set_trust_ca add_trust_ca
153
+
154
+ def add_trust_ca_to_store(cert_store, trust_ca_file_or_hashed_dir)
149
155
  if FileTest.directory?(trust_ca_file_or_hashed_dir)
150
- @cert_store.add_path(trust_ca_file_or_hashed_dir)
156
+ cert_store.add_path(trust_ca_file_or_hashed_dir)
151
157
  else
152
- @cert_store.add_file(trust_ca_file_or_hashed_dir)
158
+ cert_store.add_file(trust_ca_file_or_hashed_dir)
153
159
  end
154
- change_notify
155
160
  end
156
- alias set_trust_ca add_trust_ca
157
161
 
158
162
  # Loads default trust anchors.
159
163
  # Calling this method resets all existing sessions.
160
164
  def load_trust_ca
161
- load_cacerts
165
+ load_cacerts(@cert_store)
162
166
  change_notify
163
167
  end
164
168
 
@@ -283,13 +287,13 @@ class HTTPClient
283
287
  # Default callback for verification: only dumps error.
284
288
  def default_verify_callback(is_ok, ctx)
285
289
  if $DEBUG
286
- puts "#{ is_ok ? 'ok' : 'ng' }: #{ctx.current_cert.subject}"
290
+ warn("#{ is_ok ? 'ok' : 'ng' }: #{ctx.current_cert.subject}")
287
291
  end
288
292
  if !is_ok
289
293
  depth = ctx.error_depth
290
294
  code = ctx.error
291
295
  msg = ctx.error_string
292
- STDERR.puts "at depth #{depth} - #{code}: #{msg}"
296
+ warn("at depth #{depth} - #{code}: #{msg}")
293
297
  end
294
298
  is_ok
295
299
  end
@@ -300,7 +304,7 @@ class HTTPClient
300
304
  depth = ctx.error_depth
301
305
  code = ctx.error
302
306
  msg = ctx.error_string
303
- STDERR.puts "at depth #{depth} - #{code}: #{msg}" if $DEBUG
307
+ warn("at depth #{depth} - #{code}: #{msg}") if $DEBUG
304
308
  return false
305
309
  end
306
310
 
@@ -333,13 +337,13 @@ class HTTPClient
333
337
  end
334
338
 
335
339
  if self_signed
336
- STDERR.puts 'self signing CA' if $DEBUG
340
+ warn('self signing CA') if $DEBUG
337
341
  return true
338
342
  elsif ca
339
- STDERR.puts 'middle level CA' if $DEBUG
343
+ warn('middle level CA') if $DEBUG
340
344
  return true
341
345
  elsif server_auth
342
- STDERR.puts 'for server authentication' if $DEBUG
346
+ warn('for server authentication') if $DEBUG
343
347
  return true
344
348
  end
345
349
 
@@ -352,7 +356,7 @@ class HTTPClient
352
356
  @client.reset_all
353
357
  end
354
358
 
355
- def load_cacerts
359
+ def load_cacerts(cert_store)
356
360
  [
357
361
  [DIST_CERT, 'cacert.p7s'],
358
362
  [DIST_CERT_SHA1, 'cacert_sha1.p7s']
@@ -364,12 +368,12 @@ class HTTPClient
364
368
  store = X509::Store.new
365
369
  store.add_cert(selfcert)
366
370
  if (p7.verify(nil, store, p7.data, 0))
367
- add_trust_ca(file)
371
+ add_trust_ca_to_store(cert_store, file)
368
372
  return
369
373
  end
370
374
  end
371
375
  end
372
- STDERR.puts("cacerts loading failed")
376
+ warn("cacerts loading failed")
373
377
  end
374
378
 
375
379
  DIST_CERT =<<__DIST_CERT__
@@ -0,0 +1,8 @@
1
+ require 'httpclient'
2
+
3
+ c = HTTPClient.new
4
+ conn = c.get_async("http://dev.ctor.org/")
5
+ io = conn.pop.content
6
+ while str = io.read(40)
7
+ p str
8
+ end
@@ -0,0 +1,11 @@
1
+ require 'httpclient'
2
+
3
+ c = HTTPClient.new
4
+ c.debug_dev = STDOUT
5
+
6
+ # for Proxy authentication: supports Basic, Negotiate and NTLM.
7
+ #c.set_proxy_auth("admin", "admin")
8
+
9
+ # for WWW authentication: supports Basic, Digest and Negotiate.
10
+ c.set_auth("http://dev.ctor.org/http-access2/", "user", "user")
11
+ p c.get("http://dev.ctor.org/http-access2/login")
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join('..', 'lib'))
4
+ require 'httpclient'
5
+
6
+ proxy = ENV['HTTP_PROXY']
7
+ clnt = HTTPClient.new(proxy)
8
+ clnt.set_cookie_store("cookie.dat")
9
+ clnt.debug_dev = STDOUT if $DEBUG
10
+
11
+ while urlstr = ARGV.shift
12
+ response = clnt.get(urlstr){ |data|
13
+ print data
14
+ }
15
+ p response.contenttype
16
+ end
17
+
18
+ clnt.save_cookie_store
@@ -0,0 +1,103 @@
1
+ require 'uri'
2
+ require 'httpclient'
3
+
4
+ class DAV
5
+ attr_reader :headers
6
+
7
+ def initialize(uri = nil)
8
+ @uri = nil
9
+ @headers = {}
10
+ open(uri) if uri
11
+ proxy = ENV['HTTP_PROXY'] || ENV['http_proxy'] || nil
12
+ @client = HTTPClient.new(proxy)
13
+ end
14
+
15
+ def open(uri)
16
+ @uri = if uri.is_a?(URI)
17
+ uri
18
+ else
19
+ URI.parse(uri)
20
+ end
21
+ end
22
+
23
+ def set_basic_auth(user_id, passwd)
24
+ @client.set_basic_auth(@uri, user_id, passwd)
25
+ end
26
+
27
+ # TODO: propget/propset support
28
+
29
+ def propfind(target)
30
+ target_uri = @uri + target
31
+ res = @client.propfind(target_uri)
32
+ res.body.content
33
+ end
34
+
35
+ def get(target, local = nil)
36
+ local ||= target
37
+ target_uri = @uri + target
38
+ if FileTest.exist?(local)
39
+ raise RuntimeError.new("File #{ local } exists.")
40
+ end
41
+ f = File.open(local, "wb")
42
+ res = @client.get(target_uri, nil, @headers) do |data|
43
+ f << data
44
+ end
45
+ f.close
46
+ STDOUT.puts("#{ res.header['content-length'][0] } bytes saved to file #{ target }.")
47
+ end
48
+
49
+ def debug_dev=(dev)
50
+ @client.debug_dev = dev
51
+ end
52
+
53
+ def get_content(target)
54
+ target_uri = @uri + target
55
+ @client.get_content(target_uri, nil, @headers)
56
+ end
57
+
58
+ def put_content(target, content)
59
+ target_uri = @uri + target
60
+ res = @client.put(target_uri, content, @headers)
61
+ if res.status < 200 or res.status >= 300
62
+ raise "HTTP PUT failed: #{res.inspect}"
63
+ end
64
+ end
65
+
66
+ class Mock
67
+ attr_reader :headers
68
+
69
+ def initialize(uri = nil)
70
+ @uri = nil
71
+ @headers = {}
72
+ open(uri) if uri
73
+
74
+ @cache = {}
75
+ end
76
+
77
+ def open(uri)
78
+ @uri = uri.is_a?(URI) ? uri : URI.parse(uri)
79
+ end
80
+
81
+ def set_basic_auth(user_id, passwd)
82
+ # ignore
83
+ end
84
+
85
+ def propfind(target)
86
+ # not found
87
+ nil
88
+ end
89
+
90
+ def get(target, local = nil)
91
+ # ignore
92
+ end
93
+
94
+ def get_content(target)
95
+ @cache[target]
96
+ end
97
+
98
+ def put_content(target, content)
99
+ @cache[target] = content
100
+ nil
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join('..', 'lib'))
4
+ require 'httpclient'
5
+
6
+ proxy = ENV['HTTP_PROXY']
7
+ clnt = HTTPClient.new(proxy)
8
+ clnt.set_cookie_store("cookie.dat")
9
+ target = ARGV.shift || "http://localhost/foo.cgi"
10
+
11
+ puts
12
+ puts '= GET content directly'
13
+ puts clnt.get_content(target)
14
+
15
+ puts '= GET result object'
16
+ result = clnt.get(target)
17
+ puts '== Header object'
18
+ p result.header
19
+ puts "== Content-type"
20
+ p result.contenttype
21
+ puts '== Body object'
22
+ p result.body
23
+ puts '== Content'
24
+ print result.content
25
+ puts '== GET with Block'
26
+ clnt.get(target) do |str|
27
+ puts str
28
+ end
29
+
30
+ puts
31
+ puts '= GET with query'
32
+ puts clnt.get(target, { "foo" => "bar", "baz" => "quz" }).content
33
+
34
+ puts
35
+ puts '= GET with query 2'
36
+ puts clnt.get(target, [["foo", "bar1"], ["foo", "bar2"]]).content
37
+
38
+ clnt.debug_dev = STDERR
39
+ puts
40
+ puts '= GET with extra header'
41
+ puts clnt.get(target, nil, { "SOAPAction" => "HelloWorld" }).content
42
+
43
+ puts
44
+ puts '= GET with extra header 2'
45
+ puts clnt.get(target, nil, [["Accept", "text/plain"], ["Accept", "text/html"]]).content
46
+
47
+ clnt.debug_dev = nil
48
+
49
+ clnt.save_cookie_store