httpclient 2.2.0.2 → 2.2.1

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.
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