File: net/http.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: Net#31
has properties
constant: HTTPSession #1130
constant: HTTPMovedTemporarily #1866
constant: HTTPRequestURITooLarge #1926
constant: HTTPInformationCode #2276
constant: HTTPSuccessCode #2277
constant: HTTPRedirectionCode #2278
constant: HTTPRetriableCode #2279
constant: HTTPClientErrorCode #2280
constant: HTTPFatalErrorCode #2281
constant: HTTPServerErrorCode #2282
constant: HTTPResponceReceiver #2283
  module: NetPrivate#2272
has properties
constant: HTTPRequest #2273
  class: HTTPBadResponse#34
inherits from
  StandardError ( Builtin-Module )
  class: HTTPHeaderSyntaxError#35
inherits from
  StandardError ( Builtin-Module )
  class: HTTP#278, #1604, #2269
inherits from
  Protocol ( Net )
has properties
constant: Revision #281
constant: HTTPVersion #282
class method: version_1_2 #294
class method: version_1_1 #300
class method: version_1_2? #306
class method: version_1_1? #312
class alias: is_version_1_1? version_1_1? #317
class alias: is_version_1_2? version_1_2? #318
class method: get_print / 3 #336
class method: get (1/2) / 3 #355
class method: get_response / 4 #371
class method: post_form / 2 #400
class method: default_port #414
class method: http_default_port #419
class method: https_default_port #424
class method: socket_type #428
class method: start (1/2) / 7 #439
class alias: newobj new #444
class method: new / 6 #450
method: initialize / 2 #460
method: inspect #475
method: set_debug_output / 1 #488
attribute: address [R] #494
attribute: port [R] #497
attribute: open_timeout [RW] #502
attribute: read_timeout [R] #507
method: read_timeout= / 1 #510
method: started? #516
alias: active? started? #520
attribute: close_on_empty_response [RW] #522
method: use_ssl? (1/2) #525
method: start (2/E) #538
method: do_start #552
method: connect #558
method: on_connect #595
method: finish #601
method: do_finish #606
class method: Proxy / 4 #641
class method: proxy_class? #659
class attribute: proxy_address (1/2) [R] #663
class attribute: proxy_port (1/2) [R] #664
class attribute: proxy_user (1/2) [R] #665
class attribute: proxy_pass (1/2) [R] #666
method: proxy? #670
method: proxy_address (2/E) #675
method: proxy_port (2/E) #680
method: proxy_user (2/E) #685
method: proxy_pass (2/E) #690
alias: proxyaddr proxy_address #694
alias: proxyport proxy_port #695
method: conn_address #701
method: conn_port #705
method: edit_path / 1 #709
method: get (2/E) / 4 #770
method: head / 2 #800
method: post / 5 #843
method: put / 3 #856
method: proppatch / 3 #864
method: lock / 3 #870
method: unlock / 3 #876
method: options / 2 #882
method: propfind / 3 #888
method: delete / 2 #894
method: move / 2 #900
method: copy / 2 #906
method: mkcol / 3 #912
method: trace / 2 #918
method: request_get / 3 #947
method: request_head / 3 #961
method: request_post / 4 #991
method: request_put / 4 #995
alias: get2 request_get #999
alias: head2 request_head #1000
alias: post2 request_post #1001
alias: put2 request_put #1002
method: send_request / 4 #1015
method: request / 3 #1033
method: begin_transport / 1 #1068
method: end_transport / 2 #1081
method: keep_alive? / 2 #1098
method: addr_port #1114
method: D / 1 #1122
constant: ProxyMod #2270
  module: ProxyDelta#713
has properties
method: conn_address #716
method: conn_port #720
method: edit_path / 1 #724
  class: Get#1609
inherits from
  HTTPRequest ( Net )
has properties
constant: METHOD #1610
constant: REQUEST_HAS_BODY #1611
constant: RESPONSE_HAS_BODY #1612
  class: Head#1615
inherits from
  HTTPRequest ( Net )
has properties
constant: METHOD #1616
constant: REQUEST_HAS_BODY #1617
constant: RESPONSE_HAS_BODY #1618
  class: Post#1621
inherits from
  HTTPRequest ( Net )
has properties
constant: METHOD #1622
constant: REQUEST_HAS_BODY #1623
constant: RESPONSE_HAS_BODY #1624
  class: Put#1627
inherits from
  HTTPRequest ( Net )
has properties
constant: METHOD #1628
constant: REQUEST_HAS_BODY #1629
constant: RESPONSE_HAS_BODY #1630
  class: Delete#1633
inherits from
  HTTPRequest ( Net )
has properties
constant: METHOD #1634
constant: REQUEST_HAS_BODY #1635
constant: RESPONSE_HAS_BODY #1636
  class: Options#1639
inherits from
  HTTPRequest ( Net )
has properties
constant: METHOD #1640
constant: REQUEST_HAS_BODY #1641
constant: RESPONSE_HAS_BODY #1642
  class: Trace#1645
inherits from
  HTTPRequest ( Net )
has properties
constant: METHOD #1646
constant: REQUEST_HAS_BODY #1647
constant: RESPONSE_HAS_BODY #1648
  class: Propfind#1655
inherits from
  HTTPRequest ( Net )
has properties
constant: METHOD #1656
constant: REQUEST_HAS_BODY #1657
constant: RESPONSE_HAS_BODY #1658
  class: Proppatch#1661
inherits from
  HTTPRequest ( Net )
has properties
constant: METHOD #1662
constant: REQUEST_HAS_BODY #1663
constant: RESPONSE_HAS_BODY #1664
  class: Mkcol#1667
inherits from
  HTTPRequest ( Net )
has properties
constant: METHOD #1668
constant: REQUEST_HAS_BODY #1669
constant: RESPONSE_HAS_BODY #1670
  class: Copy#1673
inherits from
  HTTPRequest ( Net )
has properties
constant: METHOD #1674
constant: REQUEST_HAS_BODY #1675
constant: RESPONSE_HAS_BODY #1676
  class: Move#1679
inherits from
  HTTPRequest ( Net )
has properties
constant: METHOD #1680
constant: REQUEST_HAS_BODY #1681
constant: RESPONSE_HAS_BODY #1682
  class: Lock#1685
inherits from
  HTTPRequest ( Net )
has properties
constant: METHOD #1686
constant: REQUEST_HAS_BODY #1687
constant: RESPONSE_HAS_BODY #1688
  class: Unlock#1691
inherits from
  HTTPRequest ( Net )
has properties
constant: METHOD #1692
constant: REQUEST_HAS_BODY #1693
constant: RESPONSE_HAS_BODY #1694
  module: HTTPHeader#1141
has properties
method: initialize_http_header / 1 #1143
method: size #1152
alias: length size #1156
method: [] / 1 #1160
method: []= / 2 #1166
method: add_field / 2 #1189
method: get_fields / 1 #1208
method: fetch / 3 #1216
method: each_header #1222
alias: each each_header #1228
method: each_name / 1 #1231
alias: each_key each_name #1235
method: each_capitalized_name / 1 #1238
method: each_value #1245
method: delete / 1 #1252
method: key? / 1 #1257
method: to_hash #1262
method: each_capitalized #1267
alias: canonical_each each_capitalized #1273
method: capitalize / 1 #1275
method: range #1282
method: set_range / 2 #1304
alias: range= set_range #1333
method: content_length #1337
method: content_length= / 1 #1344
method: chunked? #1356
method: content_range #1365
method: range_length #1373
method: content_type #1380
method: main_type #1390
method: sub_type #1398
method: type_params #1407
method: set_content_type / 2 #1420
alias: content_type= set_content_type #1424
method: set_form_data / 2 #1432
alias: form_data= set_form_data #1437
method: urlencode / 1 #1439
method: basic_auth / 2 #1445
method: proxy_basic_auth / 2 #1450
method: basic_encode / 2 #1454
  class: HTTPGenericRequest#1468
includes
  HTTPHeader ( Net )
inherits from
  Object ( Builtin-Module )
has properties
constant: BUFSIZE #1472
method: initialize / 5 #1474
attribute: method [R] #1486
attribute: path [R] #1487
method: inspect #1489
method: request_body_permitted? #1493
method: response_body_permitted? #1497
method: body_exist? #1501
attribute: body [R] #1506
method: body= / 1 #1508
attribute: body_stream [R] #1514
method: body_stream= / 1 #1516
method: set_body_internal / 1 #1522
method: exec / 3 #1531
method: send_request_with_body / 4 #1543
method: send_request_with_body_stream / 4 #1551
method: supply_default_content_type #1570
method: write_header / 3 #1576
  class: HTTPRequest#1592
inherits from
  HTTPGenericRequest ( Net )
has properties
method: initialize / 2 #1595
  module: HTTPExceptions#1705
has properties
method: initialize / 2 #1706
attribute: response [R] #1710
alias: data response #1711
  class: HTTPError#1713
includes
  HTTPExceptions ( Net )
inherits from
  ProtocolError ( Net )
  class: HTTPRetriableError#1716
includes
  HTTPExceptions ( Net )
inherits from
  ProtoRetriableError ( Net )
  class: HTTPServerException#1719
includes
  HTTPExceptions ( Net )
inherits from
  ProtoServerError ( Net )
  class: HTTPFatalError#1723
includes
  HTTPExceptions ( Net )
inherits from
  ProtoFatalError ( Net )
  class: HTTPResponse#1790, #1959
includes
  HTTPHeader ( Net )
inherits from
  Object ( Builtin-Module )
has properties
class method: body_permitted? #1792
class method: exception_type #1796
constant: CODE_CLASS_TO_OBJ #1961
constant: CODE_TO_OBJ #1968
class method: read_new / 1 #2016
class method: read_status_line / 1 #2027
class method: response_class / 1 #2034
class method: each_response_header / 1 #2040
method: initialize / 3 #2057
attribute: http_version [R] #2067
attribute: code [R] #2072
attribute: message [R] #2075
alias: msg message #2076
method: inspect #2078
method: to_ary #2087
method: code_type #2100
method: error! #2104
method: error_type #2108
method: value #2113
method: response #2121
method: header #2126
method: read_header #2131
method: reading_body / 2 #2140
method: read_body / 2 #2173
method: body #2205
alias: entity body #2209
method: read_body_0 / 1 #2213
method: read_chunked / 1 #2231
method: stream_check #2248
method: procdest / 2 #2252
  class: HTTPUnknownResponse#1803
inherits from
  HTTPResponse ( Net )
has properties
constant: HAS_BODY #1804
constant: EXCEPTION_TYPE #1805
  class: HTTPInformation#1807
inherits from
  HTTPResponse ( Net )
has properties
constant: HAS_BODY #1808
constant: EXCEPTION_TYPE #1809
  class: HTTPSuccess#1811
inherits from
  HTTPResponse ( Net )
has properties
constant: HAS_BODY #1812
constant: EXCEPTION_TYPE #1813
  class: HTTPRedirection#1815
inherits from
  HTTPResponse ( Net )
has properties
constant: HAS_BODY #1816
constant: EXCEPTION_TYPE #1817
  class: HTTPClientError#1819
inherits from
  HTTPResponse ( Net )
has properties
constant: HAS_BODY #1820
constant: EXCEPTION_TYPE #1821
  class: HTTPServerError#1823
inherits from
  HTTPResponse ( Net )
has properties
constant: HAS_BODY #1824
constant: EXCEPTION_TYPE #1825
  class: HTTPContinue#1828
inherits from
  HTTPInformation ( Net )
has properties
constant: HAS_BODY #1829
  class: HTTPSwitchProtocol#1831
inherits from
  HTTPInformation ( Net )
has properties
constant: HAS_BODY #1832
  class: HTTPOK#1835
inherits from
  HTTPSuccess ( Net )
has properties
constant: HAS_BODY #1836
  class: HTTPCreated#1838
inherits from
  HTTPSuccess ( Net )
has properties
constant: HAS_BODY #1839
  class: HTTPAccepted#1841
inherits from
  HTTPSuccess ( Net )
has properties
constant: HAS_BODY #1842
  class: HTTPNonAuthoritativeInformation#1844
inherits from
  HTTPSuccess ( Net )
has properties
constant: HAS_BODY #1845
  class: HTTPNoContent#1847
inherits from
  HTTPSuccess ( Net )
has properties
constant: HAS_BODY #1848
  class: HTTPResetContent#1850
inherits from
  HTTPSuccess ( Net )
has properties
constant: HAS_BODY #1851
  class: HTTPPartialContent#1853
inherits from
  HTTPSuccess ( Net )
has properties
constant: HAS_BODY #1854
  class: HTTPMultipleChoice#1857
inherits from
  HTTPRedirection ( Net )
has properties
constant: HAS_BODY #1858
  class: HTTPMovedPermanently#1860
inherits from
  HTTPRedirection ( Net )
has properties
constant: HAS_BODY #1861
  class: HTTPFound#1863
inherits from
  HTTPRedirection ( Net )
has properties
constant: HAS_BODY #1864
  class: HTTPSeeOther#1867
inherits from
  HTTPRedirection ( Net )
has properties
constant: HAS_BODY #1868
  class: HTTPNotModified#1870
inherits from
  HTTPRedirection ( Net )
has properties
constant: HAS_BODY #1871
  class: HTTPUseProxy#1873
inherits from
  HTTPRedirection ( Net )
has properties
constant: HAS_BODY #1874
  class: HTTPTemporaryRedirect#1877
inherits from
  HTTPRedirection ( Net )
has properties
constant: HAS_BODY #1878
  class: HTTPBadRequest#1881
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1882
  class: HTTPUnauthorized#1884
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1885
  class: HTTPPaymentRequired#1887
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1888
  class: HTTPForbidden#1890
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1891
  class: HTTPNotFound#1893
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1894
  class: HTTPMethodNotAllowed#1896
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1897
  class: HTTPNotAcceptable#1899
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1900
  class: HTTPProxyAuthenticationRequired#1902
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1903
  class: HTTPRequestTimeOut#1905
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1906
  class: HTTPConflict#1908
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1909
  class: HTTPGone#1911
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1912
  class: HTTPLengthRequired#1914
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1915
  class: HTTPPreconditionFailed#1917
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1918
  class: HTTPRequestEntityTooLarge#1920
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1921
  class: HTTPRequestURITooLong#1923
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1924
  class: HTTPUnsupportedMediaType#1927
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1928
  class: HTTPRequestedRangeNotSatisfiable#1930
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1931
  class: HTTPExpectationFailed#1933
inherits from
  HTTPClientError ( Net )
has properties
constant: HAS_BODY #1934
  class: HTTPInternalServerError#1937
inherits from
  HTTPServerError ( Net )
has properties
constant: HAS_BODY #1938
  class: HTTPNotImplemented#1940
inherits from
  HTTPServerError ( Net )
has properties
constant: HAS_BODY #1941
  class: HTTPBadGateway#1943
inherits from
  HTTPServerError ( Net )
has properties
constant: HAS_BODY #1944
  class: HTTPServiceUnavailable#1946
inherits from
  HTTPServerError ( Net )
has properties
constant: HAS_BODY #1947
  class: HTTPGatewayTimeOut#1949
inherits from
  HTTPServerError ( Net )
has properties
constant: HAS_BODY #1950
  class: HTTPVersionNotSupported#1952
inherits from
  HTTPServerError ( Net )
has properties
constant: HAS_BODY #1953

Class Hierarchy

Object ( Builtin-Module )
Exception ( Builtin-Module )
Protocol ( Net )
  HTTP    #278, #1604, #2269
HTTPGenericRequest ( Net ) — #1468
HTTPRequest ( Net ) — #1592
  Get ( Net::HTTP ) #1609
  Head ( Net::HTTP ) #1615
  Post ( Net::HTTP ) #1621
  Put ( Net::HTTP ) #1627
  Delete ( Net::HTTP ) #1633
  Options ( Net::HTTP ) #1639
  Trace ( Net::HTTP ) #1645
  Propfind ( Net::HTTP ) #1655
  Proppatch ( Net::HTTP ) #1661
  Mkcol ( Net::HTTP ) #1667
  Copy ( Net::HTTP ) #1673
  Move ( Net::HTTP ) #1679
  Lock ( Net::HTTP ) #1685
  Unlock ( Net::HTTP ) #1691
HTTPResponse ( Net ) — #1790, #1959
HTTPUnknownResponse ( Net ) — #1803
HTTPInformation ( Net ) — #1807
  HTTPContinue    #1828
  HTTPSwitchProtocol    #1831
HTTPSuccess ( Net ) — #1811
  HTTPOK    #1835
  HTTPCreated    #1838
  HTTPAccepted    #1841
  HTTPNonAuthoritativeInformation    #1844
  HTTPNoContent    #1847
  HTTPResetContent    #1850
  HTTPPartialContent    #1853
HTTPRedirection ( Net ) — #1815
  HTTPMultipleChoice    #1857
  HTTPMovedPermanently    #1860
  HTTPFound    #1863
  HTTPSeeOther    #1867
  HTTPNotModified    #1870
  HTTPUseProxy    #1873
  HTTPTemporaryRedirect    #1877
HTTPClientError ( Net ) — #1819
  HTTPBadRequest    #1881
  HTTPUnauthorized    #1884
  HTTPPaymentRequired    #1887
  HTTPForbidden    #1890
  HTTPNotFound    #1893
  HTTPMethodNotAllowed    #1896
  HTTPNotAcceptable    #1899
  HTTPProxyAuthenticationRequired    #1902
  HTTPRequestTimeOut    #1905
  HTTPConflict    #1908
  HTTPGone    #1911
  HTTPLengthRequired    #1914
  HTTPPreconditionFailed    #1917
  HTTPRequestEntityTooLarge    #1920
  HTTPRequestURITooLong    #1923
  HTTPUnsupportedMediaType    #1927
  HTTPRequestedRangeNotSatisfiable    #1930
  HTTPExpectationFailed    #1933
HTTPServerError ( Net ) — #1823
  HTTPInternalServerError    #1937
  HTTPNotImplemented    #1940
  HTTPBadGateway    #1943
  HTTPServiceUnavailable    #1946
  HTTPGatewayTimeOut    #1949
  HTTPVersionNotSupported    #1952

Code

   1  #
   2  # = net/http.rb
   3  #
   4  # Copyright (c) 1999-2006 Yukihiro Matsumoto
   5  # Copyright (c) 1999-2006 Minero Aoki
   6  # Copyright (c) 2001 GOTOU Yuuzou
   7  # 
   8  # Written and maintained by Minero Aoki <aamine@loveruby.net>.
   9  # HTTPS support added by GOTOU Yuuzou <gotoyuzo@notwork.org>.
  10  #
  11  # This file is derived from "http-access.rb".
  12  #
  13  # Documented by Minero Aoki; converted to RDoc by William Webber.
  14  # 
  15  # This program is free software. You can re-distribute and/or
  16  # modify this program under the same terms of ruby itself ---
  17  # Ruby Distribution License or GNU General Public License.
  18  #
  19  # See Net::HTTP for an overview and examples. 
  20  # 
  21  # NOTE: You can find Japanese version of this document here:
  22  # http://www.ruby-lang.org/ja/man/?cmd=view;name=net%2Fhttp.rb
  23  # 
  24  #--
  25  # $Id: http.rb 29865 2010-11-22 07:22:19Z shyouhei $
  26  #++ 
  27 
  28  require 'net/protocol'
  29  require 'uri'
  30 
  31  module Net   #:nodoc:
  32 
  33    # :stopdoc:
  34    class HTTPBadResponse < StandardError; end
  35    class HTTPHeaderSyntaxError < StandardError; end
  36    # :startdoc:
  37 
  38    # == What Is This Library?
  39    # 
  40    # This library provides your program functions to access WWW
  41    # documents via HTTP, Hyper Text Transfer Protocol version 1.1.
  42    # For details of HTTP, refer [RFC2616]
  43    # (http://www.ietf.org/rfc/rfc2616.txt).
  44    # 
  45    # == Examples
  46    # 
  47    # === Getting Document From WWW Server
  48    # 
  49    # Example #1: Simple GET+print
  50    # 
  51    #     require 'net/http'
  52    #     Net::HTTP.get_print 'www.example.com', '/index.html'
  53    # 
  54    # Example #2: Simple GET+print by URL
  55    # 
  56    #     require 'net/http'
  57    #     require 'uri'
  58    #     Net::HTTP.get_print URI.parse('http://www.example.com/index.html')
  59    # 
  60    # Example #3: More generic GET+print
  61    # 
  62    #     require 'net/http'
  63    #     require 'uri'
  64    #
  65    #     url = URI.parse('http://www.example.com/index.html')
  66    #     res = Net::HTTP.start(url.host, url.port) {|http|
  67    #       http.get('/index.html')
  68    #     }
  69    #     puts res.body
  70    #
  71    # Example #4: More generic GET+print
  72    # 
  73    #     require 'net/http'
  74    #
  75    #     url = URI.parse('http://www.example.com/index.html')
  76    #     req = Net::HTTP::Get.new(url.path)
  77    #     res = Net::HTTP.start(url.host, url.port) {|http|
  78    #       http.request(req)
  79    #     }
  80    #     puts res.body
  81    # 
  82    # === Posting Form Data
  83    # 
  84    #     require 'net/http'
  85    #     require 'uri'
  86    #
  87    #     #1: Simple POST
  88    #     res = Net::HTTP.post_form(URI.parse('http://www.example.com/search.cgi'),
  89    #                               {'q'=>'ruby', 'max'=>'50'})
  90    #     puts res.body
  91    #
  92    #     #2: POST with basic authentication
  93    #     res = Net::HTTP.post_form(URI.parse('http://jack:pass@www.example.com/todo.cgi'),
  94    #                                         {'from'=>'2005-01-01', 'to'=>'2005-03-31'})
  95    #     puts res.body
  96    #
  97    #     #3: Detailed control
  98    #     url = URI.parse('http://www.example.com/todo.cgi')
  99    #     req = Net::HTTP::Post.new(url.path)
 100    #     req.basic_auth 'jack', 'pass'
 101    #     req.set_form_data({'from'=>'2005-01-01', 'to'=>'2005-03-31'}, ';')
 102    #     res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }
 103    #     case res
 104    #     when Net::HTTPSuccess, Net::HTTPRedirection
 105    #       # OK
 106    #     else
 107    #       res.error!
 108    #     end
 109    # 
 110    # === Accessing via Proxy
 111    # 
 112    # Net::HTTP.Proxy creates http proxy class. It has same
 113    # methods of Net::HTTP but its instances always connect to
 114    # proxy, instead of given host.
 115    # 
 116    #     require 'net/http'
 117    # 
 118    #     proxy_addr = 'your.proxy.host'
 119    #     proxy_port = 8080
 120    #             :
 121    #     Net::HTTP::Proxy(proxy_addr, proxy_port).start('www.example.com') {|http|
 122    #       # always connect to your.proxy.addr:8080
 123    #             :
 124    #     }
 125    # 
 126    # Since Net::HTTP.Proxy returns Net::HTTP itself when proxy_addr is nil,
 127    # there's no need to change code if there's proxy or not.
 128    # 
 129    # There are two additional parameters in Net::HTTP.Proxy which allow to
 130    # specify proxy user name and password:
 131    # 
 132    #     Net::HTTP::Proxy(proxy_addr, proxy_port, proxy_user = nil, proxy_pass = nil)
 133    # 
 134    # You may use them to work with authorization-enabled proxies:
 135    # 
 136    #     require 'net/http'
 137    #     require 'uri'
 138    #     
 139    #     proxy_host = 'your.proxy.host'
 140    #     proxy_port = 8080
 141    #     uri = URI.parse(ENV['http_proxy'])
 142    #     proxy_user, proxy_pass = uri.userinfo.split(/:/) if uri.userinfo
 143    #     Net::HTTP::Proxy(proxy_host, proxy_port,
 144    #                      proxy_user, proxy_pass).start('www.example.com') {|http|
 145    #       # always connect to your.proxy.addr:8080 using specified username and password
 146    #             :
 147    #     }
 148    #
 149    # Note that net/http never rely on HTTP_PROXY environment variable.
 150    # If you want to use proxy, set it explicitly.
 151    # 
 152    # === Following Redirection
 153    # 
 154    #     require 'net/http'
 155    #     require 'uri'
 156    # 
 157    #     def fetch(uri_str, limit = 10)
 158    #       # You should choose better exception. 
 159    #       raise ArgumentError, 'HTTP redirect too deep' if limit == 0
 160    # 
 161    #       response = Net::HTTP.get_response(URI.parse(uri_str))
 162    #       case response
 163    #       when Net::HTTPSuccess     then response
 164    #       when Net::HTTPRedirection then fetch(response['location'], limit - 1)
 165    #       else
 166    #         response.error!
 167    #       end
 168    #     end
 169    # 
 170    #     print fetch('http://www.ruby-lang.org')
 171    # 
 172    # Net::HTTPSuccess and Net::HTTPRedirection is a HTTPResponse class.
 173    # All HTTPResponse objects belong to its own response class which
 174    # indicate HTTP result status. For details of response classes,
 175    # see section "HTTP Response Classes".
 176    # 
 177    # === Basic Authentication
 178    # 
 179    #     require 'net/http'
 180    # 
 181    #     Net::HTTP.start('www.example.com') {|http|
 182    #       req = Net::HTTP::Get.new('/secret-page.html')
 183    #       req.basic_auth 'account', 'password'
 184    #       response = http.request(req)
 185    #       print response.body
 186    #     }
 187    # 
 188    # === HTTP Request Classes
 189    #
 190    # Here is HTTP request class hierarchy.
 191    #
 192    #   Net::HTTPRequest
 193    #       Net::HTTP::Get
 194    #       Net::HTTP::Head
 195    #       Net::HTTP::Post
 196    #       Net::HTTP::Put
 197    #       Net::HTTP::Proppatch
 198    #       Net::HTTP::Lock
 199    #       Net::HTTP::Unlock
 200    #       Net::HTTP::Options
 201    #       Net::HTTP::Propfind
 202    #       Net::HTTP::Delete
 203    #       Net::HTTP::Move
 204    #       Net::HTTP::Copy
 205    #       Net::HTTP::Mkcol
 206    #       Net::HTTP::Trace
 207    #
 208    # === HTTP Response Classes
 209    #
 210    # Here is HTTP response class hierarchy.
 211    # All classes are defined in Net module.
 212    #
 213    #   HTTPResponse
 214    #       HTTPUnknownResponse
 215    #       HTTPInformation                    # 1xx
 216    #           HTTPContinue                       # 100
 217    #           HTTPSwitchProtocl                  # 101
 218    #       HTTPSuccess                        # 2xx
 219    #           HTTPOK                             # 200
 220    #           HTTPCreated                        # 201
 221    #           HTTPAccepted                       # 202
 222    #           HTTPNonAuthoritativeInformation    # 203
 223    #           HTTPNoContent                      # 204
 224    #           HTTPResetContent                   # 205
 225    #           HTTPPartialContent                 # 206
 226    #       HTTPRedirection                    # 3xx
 227    #           HTTPMultipleChoice                 # 300
 228    #           HTTPMovedPermanently               # 301
 229    #           HTTPFound                          # 302
 230    #           HTTPSeeOther                       # 303
 231    #           HTTPNotModified                    # 304
 232    #           HTTPUseProxy                       # 305
 233    #           HTTPTemporaryRedirect              # 307
 234    #       HTTPClientError                    # 4xx
 235    #           HTTPBadRequest                     # 400
 236    #           HTTPUnauthorized                   # 401
 237    #           HTTPPaymentRequired                # 402
 238    #           HTTPForbidden                      # 403
 239    #           HTTPNotFound                       # 404
 240    #           HTTPMethodNotAllowed               # 405
 241    #           HTTPNotAcceptable                  # 406
 242    #           HTTPProxyAuthenticationRequired    # 407
 243    #           HTTPRequestTimeOut                 # 408
 244    #           HTTPConflict                       # 409
 245    #           HTTPGone                           # 410
 246    #           HTTPLengthRequired                 # 411
 247    #           HTTPPreconditionFailed             # 412
 248    #           HTTPRequestEntityTooLarge          # 413
 249    #           HTTPRequestURITooLong              # 414
 250    #           HTTPUnsupportedMediaType           # 415
 251    #           HTTPRequestedRangeNotSatisfiable   # 416
 252    #           HTTPExpectationFailed              # 417
 253    #       HTTPServerError                    # 5xx
 254    #           HTTPInternalServerError            # 500
 255    #           HTTPNotImplemented                 # 501
 256    #           HTTPBadGateway                     # 502
 257    #           HTTPServiceUnavailable             # 503
 258    #           HTTPGatewayTimeOut                 # 504
 259    #           HTTPVersionNotSupported            # 505
 260    # 
 261    # == Switching Net::HTTP versions
 262    # 
 263    # You can use net/http.rb 1.1 features (bundled with Ruby 1.6)
 264    # by calling HTTP.version_1_1. Calling Net::HTTP.version_1_2
 265    # allows you to use 1.2 features again.
 266    # 
 267    #     # example
 268    #     Net::HTTP.start {|http1| ...(http1 has 1.2 features)... }
 269    # 
 270    #     Net::HTTP.version_1_1
 271    #     Net::HTTP.start {|http2| ...(http2 has 1.1 features)... }
 272    # 
 273    #     Net::HTTP.version_1_2
 274    #     Net::HTTP.start {|http3| ...(http3 has 1.2 features)... }
 275    # 
 276    # This function is NOT thread-safe.
 277    #
 278    class HTTP < Protocol
 279 
 280      # :stopdoc:
 281      Revision = %q$Revision: 29865 $.split[1]
 282      HTTPVersion = '1.1'
 283      @newimpl = true
 284      # :startdoc:
 285 
 286      # Turns on net/http 1.2 (ruby 1.8) features.
 287      # Defaults to ON in ruby 1.8.
 288      #
 289      # I strongly recommend to call this method always.
 290      #
 291      #   require 'net/http'
 292      #   Net::HTTP.version_1_2
 293      #
 294      def HTTP.version_1_2
 295        @newimpl = true
 296      end
 297 
 298      # Turns on net/http 1.1 (ruby 1.6) features.
 299      # Defaults to OFF in ruby 1.8.
 300      def HTTP.version_1_1
 301        @newimpl = false
 302      end
 303 
 304      # true if net/http is in version 1.2 mode.
 305      # Defaults to true.
 306      def HTTP.version_1_2?
 307        @newimpl
 308      end
 309 
 310      # true if net/http is in version 1.1 compatible mode.
 311      # Defaults to true.
 312      def HTTP.version_1_1?
 313        not @newimpl
 314      end
 315 
 316      class << HTTP
 317        alias is_version_1_1? version_1_1?   #:nodoc:
 318        alias is_version_1_2? version_1_2?   #:nodoc:
 319      end
 320 
 321      #
 322      # short cut methods
 323      #
 324 
 325      #
 326      # Get body from target and output it to +$stdout+.  The
 327      # target can either be specified as (+uri+), or as
 328      # (+host+, +path+, +port+ = 80); so: 
 329      #
 330      #    Net::HTTP.get_print URI.parse('http://www.example.com/index.html')
 331      #
 332      # or:
 333      #
 334      #    Net::HTTP.get_print 'www.example.com', '/index.html'
 335      #
 336      def HTTP.get_print(uri_or_host, path = nil, port = nil)
 337        get_response(uri_or_host, path, port) {|res|
 338          res.read_body do |chunk|
 339            $stdout.print chunk
 340          end
 341        }
 342        nil
 343      end
 344 
 345      # Send a GET request to the target and return the response
 346      # as a string.  The target can either be specified as
 347      # (+uri+), or as (+host+, +path+, +port+ = 80); so:
 348      # 
 349      #    print Net::HTTP.get(URI.parse('http://www.example.com/index.html'))
 350      #
 351      # or:
 352      #
 353      #    print Net::HTTP.get('www.example.com', '/index.html')
 354      #
 355      def HTTP.get(uri_or_host, path = nil, port = nil)
 356        get_response(uri_or_host, path, port).body
 357      end
 358 
 359      # Send a GET request to the target and return the response
 360      # as a Net::HTTPResponse object.  The target can either be specified as
 361      # (+uri+), or as (+host+, +path+, +port+ = 80); so:
 362      # 
 363      #    res = Net::HTTP.get_response(URI.parse('http://www.example.com/index.html'))
 364      #    print res.body
 365      #
 366      # or:
 367      #
 368      #    res = Net::HTTP.get_response('www.example.com', '/index.html')
 369      #    print res.body
 370      #
 371      def HTTP.get_response(uri_or_host, path = nil, port = nil, &block)
 372        if path
 373          host = uri_or_host
 374          new(host, port || HTTP.default_port).start {|http|
 375            return http.request_get(path, &block)
 376          }
 377        else
 378          uri = uri_or_host
 379          new(uri.host, uri.port).start {|http|
 380            return http.request_get(uri.request_uri, &block)
 381          }
 382        end
 383      end
 384 
 385      # Posts HTML form data to the +URL+.
 386      # Form data must be represented as a Hash of String to String, e.g:
 387      #
 388      #   { "cmd" => "search", "q" => "ruby", "max" => "50" }
 389      #
 390      # This method also does Basic Authentication iff +URL+.user exists.
 391      #
 392      # Example:
 393      #
 394      #   require 'net/http'
 395      #   require 'uri'
 396      #
 397      #   HTTP.post_form URI.parse('http://www.example.com/search.cgi'),
 398      #                  { "q" => "ruby", "max" => "50" }
 399      #
 400      def HTTP.post_form(url, params)
 401        req = Post.new(url.path)
 402        req.form_data = params
 403        req.basic_auth url.user, url.password if url.user
 404        new(url.host, url.port).start {|http|
 405          http.request(req)
 406        }
 407      end
 408 
 409      #
 410      # HTTP session management
 411      #
 412 
 413      # The default port to use for HTTP requests; defaults to 80.
 414      def HTTP.default_port
 415        http_default_port()
 416      end
 417 
 418      # The default port to use for HTTP requests; defaults to 80.
 419      def HTTP.http_default_port
 420        80
 421      end
 422 
 423      # The default port to use for HTTPS requests; defaults to 443.
 424      def HTTP.https_default_port
 425        443
 426      end
 427 
 428      def HTTP.socket_type   #:nodoc: obsolete
 429        BufferedIO
 430      end
 431 
 432      # creates a new Net::HTTP object and opens its TCP connection and 
 433      # HTTP session.  If the optional block is given, the newly 
 434      # created Net::HTTP object is passed to it and closed when the 
 435      # block finishes.  In this case, the return value of this method
 436      # is the return value of the block.  If no block is given, the
 437      # return value of this method is the newly created Net::HTTP object
 438      # itself, and the caller is responsible for closing it upon completion.
 439      def HTTP.start(address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil, &block) # :yield: +http+
 440        new(address, port, p_addr, p_port, p_user, p_pass).start(&block)
 441      end
 442 
 443      class << HTTP
 444        alias newobj new
 445      end
 446 
 447      # Creates a new Net::HTTP object.
 448      # If +proxy_addr+ is given, creates an Net::HTTP object with proxy support.
 449      # This method does not open the TCP connection.
 450      def HTTP.new(address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil)
 451        h = Proxy(p_addr, p_port, p_user, p_pass).newobj(address, port)
 452        h.instance_eval {
 453          @newimpl = ::Net::HTTP.version_1_2?
 454        }
 455        h
 456      end
 457 
 458      # Creates a new Net::HTTP object for the specified +address+.
 459      # This method does not open the TCP connection.
 460      def initialize(address, port = nil)
 461        @address = address
 462        @port    = (port || HTTP.default_port)
 463        @curr_http_version = HTTPVersion
 464        @seems_1_0_server = false
 465        @close_on_empty_response = false
 466        @socket  = nil
 467        @started = false
 468        @open_timeout = nil
 469        @read_timeout = 60
 470        @debug_output = nil
 471        @use_ssl = false
 472        @ssl_context = nil
 473      end
 474 
 475      def inspect
 476        "#<#{self.class} #{@address}:#{@port} open=#{started?}>"
 477      end
 478 
 479      # *WARNING* This method causes serious security hole.
 480      # Never use this method in production code.
 481      #
 482      # Set an output stream for debugging.
 483      #
 484      #   http = Net::HTTP.new
 485      #   http.set_debug_output $stderr
 486      #   http.start { .... }
 487      #
 488      def set_debug_output(output)
 489        warn 'Net::HTTP#set_debug_output called after HTTP started' if started?
 490        @debug_output = output
 491      end
 492 
 493      # The host name to connect to.
 494      attr_reader :address
 495 
 496      # The port number to connect to.
 497      attr_reader :port
 498 
 499      # Seconds to wait until connection is opened.
 500      # If the HTTP object cannot open a connection in this many seconds,
 501      # it raises a TimeoutError exception.
 502      attr_accessor :open_timeout
 503 
 504      # Seconds to wait until reading one block (by one read(2) call).
 505      # If the HTTP object cannot open a connection in this many seconds,
 506      # it raises a TimeoutError exception.
 507      attr_reader :read_timeout
 508 
 509      # Setter for the read_timeout attribute.
 510      def read_timeout=(sec)
 511        @socket.read_timeout = sec if @socket
 512        @read_timeout = sec
 513      end
 514 
 515      # returns true if the HTTP session is started.
 516      def started?
 517        @started
 518      end
 519 
 520      alias active? started?   #:nodoc: obsolete
 521 
 522      attr_accessor :close_on_empty_response
 523 
 524      # returns true if use SSL/TLS with HTTP.
 525      def use_ssl?
 526        false   # redefined in net/https
 527      end
 528 
 529      # Opens TCP connection and HTTP session.
 530      # 
 531      # When this method is called with block, gives a HTTP object
 532      # to the block and closes the TCP connection / HTTP session
 533      # after the block executed.
 534      #
 535      # When called with a block, returns the return value of the
 536      # block; otherwise, returns self.
 537      #
 538      def start  # :yield: http
 539        raise IOError, 'HTTP session already opened' if @started
 540        if block_given?
 541          begin
 542            do_start
 543            return yield(self)
 544          ensure
 545            do_finish
 546          end
 547        end
 548        do_start
 549        self
 550      end
 551 
 552      def do_start
 553        connect
 554        @started = true
 555      end
 556      private :do_start
 557 
 558      def connect
 559        D "opening connection to #{conn_address()}..."
 560        s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) }
 561        D "opened"
 562        if use_ssl?
 563          unless @ssl_context.verify_mode
 564            warn "warning: peer certificate won't be verified in this SSL session"
 565            @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
 566          end
 567          s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
 568          s.sync_close = true
 569        end
 570        @socket = BufferedIO.new(s)
 571        @socket.read_timeout = @read_timeout
 572        @socket.debug_output = @debug_output
 573        if use_ssl?
 574          if proxy?
 575            @socket.writeline sprintf('CONNECT %s:%s HTTP/%s',
 576                                      @address, @port, HTTPVersion)
 577            @socket.writeline "Host: #{@address}:#{@port}"
 578            if proxy_user
 579              credential = ["#{proxy_user}:#{proxy_pass}"].pack('m')
 580              credential.delete!("\r\n")
 581              @socket.writeline "Proxy-Authorization: Basic #{credential}"
 582            end
 583            @socket.writeline ''
 584            HTTPResponse.read_new(@socket).value
 585          end
 586          s.connect
 587          if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE
 588            s.post_connection_check(@address)
 589          end
 590        end
 591        on_connect
 592      end
 593      private :connect
 594 
 595      def on_connect
 596      end
 597      private :on_connect
 598 
 599      # Finishes HTTP session and closes TCP connection.
 600      # Raises IOError if not started.
 601      def finish
 602        raise IOError, 'HTTP session not yet started' unless started?
 603        do_finish
 604      end
 605 
 606      def do_finish
 607        @started = false
 608        @socket.close if @socket and not @socket.closed?
 609        @socket = nil
 610      end
 611      private :do_finish
 612 
 613      #
 614      # proxy
 615      #
 616 
 617      public
 618 
 619      # no proxy
 620      @is_proxy_class = false
 621      @proxy_addr = nil
 622      @proxy_port = nil
 623      @proxy_user = nil
 624      @proxy_pass = nil
 625 
 626      # Creates an HTTP proxy class.
 627      # Arguments are address/port of proxy host and username/password
 628      # if authorization on proxy server is required.
 629      # You can replace the HTTP class with created proxy class.
 630      # 
 631      # If ADDRESS is nil, this method returns self (Net::HTTP).
 632      # 
 633      #     # Example
 634      #     proxy_class = Net::HTTP::Proxy('proxy.example.com', 8080)
 635      #                     :
 636      #     proxy_class.start('www.ruby-lang.org') {|http|
 637      #       # connecting proxy.foo.org:8080
 638      #                     :
 639      #     }
 640      # 
 641      def HTTP.Proxy(p_addr, p_port = nil, p_user = nil, p_pass = nil)
 642        return self unless p_addr
 643        delta = ProxyDelta
 644        proxyclass = Class.new(self)
 645        proxyclass.module_eval {
 646          include delta
 647          # with proxy
 648          @is_proxy_class = true
 649          @proxy_address = p_addr
 650          @proxy_port    = p_port || default_port()
 651          @proxy_user    = p_user
 652          @proxy_pass    = p_pass
 653        }
 654        proxyclass
 655      end
 656 
 657      class << HTTP
 658        # returns true if self is a class which was created by HTTP::Proxy.
 659        def proxy_class?
 660          @is_proxy_class
 661        end
 662 
 663        attr_reader :proxy_address
 664        attr_reader :proxy_port
 665        attr_reader :proxy_user
 666        attr_reader :proxy_pass
 667      end
 668 
 669      # True if self is a HTTP proxy class.
 670      def proxy?
 671        self.class.proxy_class?
 672      end
 673 
 674      # Address of proxy host. If self does not use a proxy, nil.
 675      def proxy_address
 676        self.class.proxy_address
 677      end
 678 
 679      # Port number of proxy host. If self does not use a proxy, nil.
 680      def proxy_port
 681        self.class.proxy_port
 682      end
 683 
 684      # User name for accessing proxy. If self does not use a proxy, nil.
 685      def proxy_user
 686        self.class.proxy_user
 687      end
 688 
 689      # User password for accessing proxy. If self does not use a proxy, nil.
 690      def proxy_pass
 691        self.class.proxy_pass
 692      end
 693 
 694      alias proxyaddr proxy_address   #:nodoc: obsolete
 695      alias proxyport proxy_port      #:nodoc: obsolete
 696 
 697      private
 698 
 699      # without proxy
 700 
 701      def conn_address
 702        address()
 703      end
 704 
 705      def conn_port
 706        port()
 707      end
 708 
 709      def edit_path(path)
 710        path
 711      end
 712 
 713      module ProxyDelta   #:nodoc: internal use only
 714        private
 715 
 716        def conn_address
 717          proxy_address()
 718        end
 719 
 720        def conn_port
 721          proxy_port()
 722        end
 723 
 724        def edit_path(path)
 725          use_ssl? ? path : "http://#{addr_port()}#{path}"
 726        end
 727      end
 728 
 729      #
 730      # HTTP operations
 731      #
 732 
 733      public
 734 
 735      # Gets data from +path+ on the connected-to host.
 736      # +header+ must be a Hash like { 'Accept' => '*/*', ... }.
 737      #
 738      # In version 1.1 (ruby 1.6), this method returns a pair of objects,
 739      # a Net::HTTPResponse object and the entity body string.
 740      # In version 1.2 (ruby 1.8), this method returns a Net::HTTPResponse
 741      # object.
 742      #
 743      # If called with a block, yields each fragment of the
 744      # entity body in turn as a string as it is read from
 745      # the socket.  Note that in this case, the returned response
 746      # object will *not* contain a (meaningful) body.
 747      #
 748      # +dest+ argument is obsolete.
 749      # It still works but you must not use it.
 750      #
 751      # In version 1.1, this method might raise an exception for 
 752      # 3xx (redirect). In this case you can get a HTTPResponse object
 753      # by "anException.response".
 754      #
 755      # In version 1.2, this method never raises exception.
 756      #
 757      #     # version 1.1 (bundled with Ruby 1.6)
 758      #     response, body = http.get('/index.html')
 759      #
 760      #     # version 1.2 (bundled with Ruby 1.8 or later)
 761      #     response = http.get('/index.html')
 762      #     
 763      #     # using block
 764      #     File.open('result.txt', 'w') {|f|
 765      #       http.get('/~foo/') do |str|
 766      #         f.write str
 767      #       end
 768      #     }
 769      #
 770      def get(path, initheader = nil, dest = nil, &block) # :yield: +body_segment+
 771        res = nil
 772        request(Get.new(path, initheader)) {|r|
 773          r.read_body dest, &block
 774          res = r
 775        }
 776        unless @newimpl
 777          res.value
 778          return res, res.body
 779        end
 780 
 781        res
 782      end
 783 
 784      # Gets only the header from +path+ on the connected-to host.
 785      # +header+ is a Hash like { 'Accept' => '*/*', ... }.
 786      # 
 787      # This method returns a Net::HTTPResponse object.
 788      # 
 789      # In version 1.1, this method might raise an exception for 
 790      # 3xx (redirect). On the case you can get a HTTPResponse object
 791      # by "anException.response".
 792      # In version 1.2, this method never raises an exception.
 793      # 
 794      #     response = nil
 795      #     Net::HTTP.start('some.www.server', 80) {|http|
 796      #       response = http.head('/index.html')
 797      #     }
 798      #     p response['content-type']
 799      #
 800      def head(path, initheader = nil) 
 801        res = request(Head.new(path, initheader))
 802        res.value unless @newimpl
 803        res
 804      end
 805 
 806      # Posts +data+ (must be a String) to +path+. +header+ must be a Hash
 807      # like { 'Accept' => '*/*', ... }.
 808      # 
 809      # In version 1.1 (ruby 1.6), this method returns a pair of objects, a
 810      # Net::HTTPResponse object and an entity body string.
 811      # In version 1.2 (ruby 1.8), this method returns a Net::HTTPResponse object.
 812      # 
 813      # If called with a block, yields each fragment of the
 814      # entity body in turn as a string as it are read from
 815      # the socket.  Note that in this case, the returned response
 816      # object will *not* contain a (meaningful) body.
 817      #
 818      # +dest+ argument is obsolete.
 819      # It still works but you must not use it.
 820      # 
 821      # In version 1.1, this method might raise an exception for 
 822      # 3xx (redirect). In this case you can get an HTTPResponse object
 823      # by "anException.response".
 824      # In version 1.2, this method never raises exception.
 825      # 
 826      #     # version 1.1
 827      #     response, body = http.post('/cgi-bin/search.rb', 'query=foo')
 828      # 
 829      #     # version 1.2
 830      #     response = http.post('/cgi-bin/search.rb', 'query=foo')
 831      # 
 832      #     # using block
 833      #     File.open('result.txt', 'w') {|f|
 834      #       http.post('/cgi-bin/search.rb', 'query=foo') do |str|
 835      #         f.write str
 836      #       end
 837      #     }
 838      #
 839      # You should set Content-Type: header field for POST.
 840      # If no Content-Type: field given, this method uses
 841      # "application/x-www-form-urlencoded" by default.
 842      #
 843      def post(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
 844        res = nil
 845        request(Post.new(path, initheader), data) {|r|
 846          r.read_body dest, &block
 847          res = r
 848        }
 849        unless @newimpl
 850          res.value
 851          return res, res.body
 852        end
 853        res
 854      end
 855 
 856      def put(path, data, initheader = nil)   #:nodoc:
 857        res = request(Put.new(path, initheader), data)
 858        res.value unless @newimpl
 859        res
 860      end
 861 
 862      # Sends a PROPPATCH request to the +path+ and gets a response,
 863      # as an HTTPResponse object.
 864      def proppatch(path, body, initheader = nil)
 865        request(Proppatch.new(path, initheader), body)
 866      end
 867 
 868      # Sends a LOCK request to the +path+ and gets a response,
 869      # as an HTTPResponse object.
 870      def lock(path, body, initheader = nil)
 871        request(Lock.new(path, initheader), body)
 872      end
 873 
 874      # Sends a UNLOCK request to the +path+ and gets a response,
 875      # as an HTTPResponse object.
 876      def unlock(path, body, initheader = nil)
 877        request(Unlock.new(path, initheader), body)
 878      end
 879 
 880      # Sends a OPTIONS request to the +path+ and gets a response,
 881      # as an HTTPResponse object.
 882      def options(path, initheader = nil)
 883        request(Options.new(path, initheader))
 884      end
 885 
 886      # Sends a PROPFIND request to the +path+ and gets a response,
 887      # as an HTTPResponse object.
 888      def propfind(path, body = nil, initheader = {'Depth' => '0'})
 889        request(Propfind.new(path, initheader), body)
 890      end
 891 
 892      # Sends a DELETE request to the +path+ and gets a response,
 893      # as an HTTPResponse object.
 894      def delete(path, initheader = {'Depth' => 'Infinity'})
 895        request(Delete.new(path, initheader))
 896      end
 897 
 898      # Sends a MOVE request to the +path+ and gets a response,
 899      # as an HTTPResponse object.
 900      def move(path, initheader = nil)
 901        request(Move.new(path, initheader))
 902      end
 903 
 904      # Sends a COPY request to the +path+ and gets a response,
 905      # as an HTTPResponse object.
 906      def copy(path, initheader = nil)
 907        request(Copy.new(path, initheader))
 908      end
 909 
 910      # Sends a MKCOL request to the +path+ and gets a response,
 911      # as an HTTPResponse object.
 912      def mkcol(path, body = nil, initheader = nil)
 913        request(Mkcol.new(path, initheader), body)
 914      end
 915 
 916      # Sends a TRACE request to the +path+ and gets a response,
 917      # as an HTTPResponse object.
 918      def trace(path, initheader = nil)
 919        request(Trace.new(path, initheader))
 920      end
 921 
 922      # Sends a GET request to the +path+ and gets a response,
 923      # as an HTTPResponse object.
 924      # 
 925      # When called with a block, yields an HTTPResponse object.
 926      # The body of this response will not have been read yet;
 927      # the caller can process it using HTTPResponse#read_body,
 928      # if desired.
 929      #
 930      # Returns the response.
 931      # 
 932      # This method never raises Net::* exceptions.
 933      # 
 934      #     response = http.request_get('/index.html')
 935      #     # The entity body is already read here.
 936      #     p response['content-type']
 937      #     puts response.body
 938      # 
 939      #     # using block
 940      #     http.request_get('/index.html') {|response|
 941      #       p response['content-type']
 942      #       response.read_body do |str|   # read body now
 943      #         print str
 944      #       end
 945      #     }
 946      #
 947      def request_get(path, initheader = nil, &block) # :yield: +response+
 948        request(Get.new(path, initheader), &block)
 949      end
 950 
 951      # Sends a HEAD request to the +path+ and gets a response,
 952      # as an HTTPResponse object.
 953      #
 954      # Returns the response.
 955      # 
 956      # This method never raises Net::* exceptions.
 957      # 
 958      #     response = http.request_head('/index.html')
 959      #     p response['content-type']
 960      #
 961      def request_head(path, initheader = nil, &block)
 962        request(Head.new(path, initheader), &block)
 963      end
 964 
 965      # Sends a POST request to the +path+ and gets a response,
 966      # as an HTTPResponse object.
 967      # 
 968      # When called with a block, yields an HTTPResponse object.
 969      # The body of this response will not have been read yet;
 970      # the caller can process it using HTTPResponse#read_body,
 971      # if desired.
 972      #
 973      # Returns the response.
 974      # 
 975      # This method never raises Net::* exceptions.
 976      # 
 977      #     # example
 978      #     response = http.request_post('/cgi-bin/nice.rb', 'datadatadata...')
 979      #     p response.status
 980      #     puts response.body          # body is already read
 981      # 
 982      #     # using block
 983      #     http.request_post('/cgi-bin/nice.rb', 'datadatadata...') {|response|
 984      #       p response.status
 985      #       p response['content-type']
 986      #       response.read_body do |str|   # read body now
 987      #         print str
 988      #       end
 989      #     }
 990      #
 991      def request_post(path, data, initheader = nil, &block) # :yield: +response+
 992        request Post.new(path, initheader), data, &block
 993      end
 994 
 995      def request_put(path, data, initheader = nil, &block)   #:nodoc:
 996        request Put.new(path, initheader), data, &block
 997      end
 998 
 999      alias get2   request_get    #:nodoc: obsolete
1000      alias head2  request_head   #:nodoc: obsolete
1001      alias post2  request_post   #:nodoc: obsolete
1002      alias put2   request_put    #:nodoc: obsolete
1003 
1004 
1005      # Sends an HTTP request to the HTTP server.
1006      # This method also sends DATA string if DATA is given.
1007      #
1008      # Returns a HTTPResponse object.
1009      # 
1010      # This method never raises Net::* exceptions.
1011      #
1012      #    response = http.send_request('GET', '/index.html')
1013      #    puts response.body
1014      #
1015      def send_request(name, path, data = nil, header = nil)
1016        r = HTTPGenericRequest.new(name,(data ? true : false),true,path,header)
1017        request r, data
1018      end
1019 
1020      # Sends an HTTPRequest object REQUEST to the HTTP server.
1021      # This method also sends DATA string if REQUEST is a post/put request.
1022      # Giving DATA for get/head request causes ArgumentError.
1023      # 
1024      # When called with a block, yields an HTTPResponse object.
1025      # The body of this response will not have been read yet;
1026      # the caller can process it using HTTPResponse#read_body,
1027      # if desired.
1028      #
1029      # Returns a HTTPResponse object.
1030      # 
1031      # This method never raises Net::* exceptions.
1032      #
1033      def request(req, body = nil, &block)  # :yield: +response+
1034        unless started?
1035          start {
1036            req['connection'] ||= 'close'
1037            return request(req, body, &block)
1038          }
1039        end
1040        if proxy_user()
1041          unless use_ssl?
1042            req.proxy_basic_auth proxy_user(), proxy_pass()
1043          end
1044        end
1045 
1046        req.set_body_internal body
1047        begin
1048          begin_transport req
1049          req.exec @socket, @curr_http_version, edit_path(req.path)
1050          begin
1051            res = HTTPResponse.read_new(@socket)
1052          end while res.kind_of?(HTTPContinue)
1053          res.reading_body(@socket, req.response_body_permitted?) {
1054            yield res if block_given?
1055          }
1056          end_transport req, res
1057        rescue => exception
1058          D "Conn close because of error #{exception}"
1059          @socket.close if @socket and not @socket.closed?
1060          raise exception
1061        end
1062 
1063        res
1064      end
1065 
1066      private
1067 
1068      def begin_transport(req)
1069        if @socket.closed?
1070          connect
1071        end
1072        if @seems_1_0_server
1073          req['connection'] ||= 'close'
1074        end
1075        if not req.response_body_permitted? and @close_on_empty_response
1076          req['connection'] ||= 'close'
1077        end
1078        req['host'] ||= addr_port()
1079      end
1080 
1081      def end_transport(req, res)
1082        @curr_http_version = res.http_version
1083        if not res.body and @close_on_empty_response
1084          D 'Conn close'
1085          @socket.close
1086        elsif keep_alive?(req, res)
1087          D 'Conn keep-alive'
1088          if @socket.closed?
1089            D 'Conn (but seems 1.0 server)'
1090            @seems_1_0_server = true
1091          end
1092        else
1093          D 'Conn close'
1094          @socket.close
1095        end
1096      end
1097 
1098      def keep_alive?(req, res)
1099        return false if /close/i =~ req['connection'].to_s
1100        return false if @seems_1_0_server
1101        return true  if /keep-alive/i =~ res['connection'].to_s
1102        return false if /close/i      =~ res['connection'].to_s
1103        return true  if /keep-alive/i =~ res['proxy-connection'].to_s
1104        return false if /close/i      =~ res['proxy-connection'].to_s
1105        (@curr_http_version == '1.1')
1106      end
1107 
1108      #
1109      # utils
1110      #
1111 
1112      private
1113 
1114      def addr_port
1115        if use_ssl?
1116          address() + (port == HTTP.https_default_port ? '' : ":#{port()}")
1117        else
1118          address() + (port == HTTP.http_default_port ? '' : ":#{port()}")
1119        end
1120      end
1121 
1122      def D(msg)
1123        return unless @debug_output
1124        @debug_output << msg
1125        @debug_output << "\n"
1126      end
1127 
1128    end
1129 
1130    HTTPSession = HTTP
1131 
1132 
1133    #
1134    # Header module.
1135    #
1136    # Provides access to @header in the mixed-into class as a hash-like
1137    # object, except with case-insensitive keys.  Also provides
1138    # methods for accessing commonly-used header values in a more
1139    # convenient format.
1140    #
1141    module HTTPHeader
1142 
1143      def initialize_http_header(initheader)
1144        @header = {}
1145        return unless initheader
1146        initheader.each do |key, value|
1147          warn "net/http: warning: duplicated HTTP header: #{key}" if key?(key) and $VERBOSE
1148          @header[key.downcase] = [value.strip]
1149        end
1150      end
1151 
1152      def size   #:nodoc: obsolete
1153        @header.size
1154      end
1155 
1156      alias length size   #:nodoc: obsolete
1157 
1158      # Returns the header field corresponding to the case-insensitive key.
1159      # For example, a key of "Content-Type" might return "text/html"
1160      def [](key)
1161        a = @header[key.downcase] or return nil
1162        a.join(', ')
1163      end
1164 
1165      # Sets the header field corresponding to the case-insensitive key.
1166      def []=(key, val)
1167        unless val
1168          @header.delete key.downcase
1169          return val
1170        end
1171        @header[key.downcase] = [val]
1172      end
1173 
1174      # [Ruby 1.8.3]
1175      # Adds header field instead of replace.
1176      # Second argument +val+ must be a String.
1177      # See also #[]=, #[] and #get_fields.
1178      #
1179      #   request.add_field 'X-My-Header', 'a'
1180      #   p request['X-My-Header']              #=> "a"
1181      #   p request.get_fields('X-My-Header')   #=> ["a"]
1182      #   request.add_field 'X-My-Header', 'b'
1183      #   p request['X-My-Header']              #=> "a, b"
1184      #   p request.get_fields('X-My-Header')   #=> ["a", "b"]
1185      #   request.add_field 'X-My-Header', 'c'
1186      #   p request['X-My-Header']              #=> "a, b, c"
1187      #   p request.get_fields('X-My-Header')   #=> ["a", "b", "c"]
1188      #
1189      def add_field(key, val)
1190        if @header.key?(key.downcase)
1191          @header[key.downcase].push val
1192        else
1193          @header[key.downcase] = [val]
1194        end
1195      end
1196 
1197      # [Ruby 1.8.3]
1198      # Returns an array of header field strings corresponding to the
1199      # case-insensitive +key+.  This method allows you to get duplicated
1200      # header fields without any processing.  See also #[].
1201      #
1202      #   p response.get_fields('Set-Cookie')
1203      #     #=> ["session=al98axx; expires=Fri, 31-Dec-1999 23:58:23",
1204      #          "query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"]
1205      #   p response['Set-Cookie']
1206      #     #=> "session=al98axx; expires=Fri, 31-Dec-1999 23:58:23, query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"
1207      #
1208      def get_fields(key)
1209        return nil unless @header[key.downcase]
1210        @header[key.downcase].dup
1211      end
1212 
1213      # Returns the header field corresponding to the case-insensitive key.
1214      # Returns the default value +args+, or the result of the block, or nil,
1215      # if there's no header field named key.  See Hash#fetch
1216      def fetch(key, *args, &block)   #:yield: +key+
1217        a = @header.fetch(key.downcase, *args, &block)
1218        a.join(', ')
1219      end
1220 
1221      # Iterates for each header names and values.
1222      def each_header   #:yield: +key+, +value+
1223        @header.each do |k,va|
1224          yield k, va.join(', ')
1225        end
1226      end
1227 
1228      alias each each_header
1229 
1230      # Iterates for each header names.
1231      def each_name(&block)   #:yield: +key+
1232        @header.each_key(&block)
1233      end
1234 
1235      alias each_key each_name
1236 
1237      # Iterates for each capitalized header names.
1238      def each_capitalized_name(&block)   #:yield: +key+
1239        @header.each_key do |k|
1240          yield capitalize(k)
1241        end
1242      end
1243 
1244      # Iterates for each header values.
1245      def each_value   #:yield: +value+
1246        @header.each_value do |va|
1247          yield va.join(', ')
1248        end
1249      end
1250 
1251      # Removes a header field.
1252      def delete(key)
1253        @header.delete(key.downcase)
1254      end
1255 
1256      # true if +key+ header exists.
1257      def key?(key)
1258        @header.key?(key.downcase)
1259      end
1260 
1261      # Returns a Hash consist of header names and values.
1262      def to_hash
1263        @header.dup
1264      end
1265 
1266      # As for #each_header, except the keys are provided in capitalized form.
1267      def each_capitalized
1268        @header.each do |k,v|
1269          yield capitalize(k), v.join(', ')
1270        end
1271      end
1272 
1273      alias canonical_each each_capitalized
1274 
1275      def capitalize(name)
1276        name.split(/-/).map {|s| s.capitalize }.join('-')
1277      end
1278      private :capitalize
1279 
1280      # Returns an Array of Range objects which represents Range: header field,
1281      # or +nil+ if there is no such header.
1282      def range
1283        return nil unless @header['range']
1284        self['Range'].split(/,/).map {|spec|
1285          m = /bytes\s*=\s*(\d+)?\s*-\s*(\d+)?/i.match(spec) or
1286                  raise HTTPHeaderSyntaxError, "wrong Range: #{spec}"
1287          d1 = m[1].to_i
1288          d2 = m[2].to_i
1289          if    m[1] and m[2] then  d1..d2
1290          elsif m[1]          then  d1..-1
1291          elsif          m[2] then -d2..-1
1292          else
1293            raise HTTPHeaderSyntaxError, 'range is not specified'
1294          end
1295        }
1296      end
1297 
1298      # Set Range: header from Range (arg r) or beginning index and
1299      # length from it (arg idx&len).
1300      #
1301      #   req.range = (0..1023)
1302      #   req.set_range 0, 1023
1303      #
1304      def set_range(r, e = nil)
1305        unless r
1306          @header.delete 'range'
1307          return r
1308        end
1309        r = (r...r+e) if e
1310        case r
1311        when Numeric
1312          n = r.to_i
1313          rangestr = (n > 0 ? "0-#{n-1}" : "-#{-n}")
1314        when Range
1315          first = r.first
1316          last = r.last
1317          last -= 1 if r.exclude_end?
1318          if last == -1
1319            rangestr = (first > 0 ? "#{first}-" : "-#{-first}")
1320          else
1321            raise HTTPHeaderSyntaxError, 'range.first is negative' if first < 0
1322            raise HTTPHeaderSyntaxError, 'range.last is negative' if last < 0
1323            raise HTTPHeaderSyntaxError, 'must be .first < .last' if first > last
1324            rangestr = "#{first}-#{last}"
1325          end
1326        else
1327          raise TypeError, 'Range/Integer is required'
1328        end
1329        @header['range'] = ["bytes=#{rangestr}"]
1330        r
1331      end
1332 
1333      alias range= set_range
1334 
1335      # Returns an Integer object which represents the Content-Length: header field
1336      # or +nil+ if that field is not provided.
1337      def content_length
1338        return nil unless key?('Content-Length')
1339        len = self['Content-Length'].slice(/\d+/) or
1340            raise HTTPHeaderSyntaxError, 'wrong Content-Length format'
1341        len.to_i
1342      end
1343      
1344      def content_length=(len)
1345        unless len
1346          @header.delete 'content-length'
1347          return nil
1348        end
1349        @header['content-length'] = [len.to_i.to_s]
1350      end
1351 
1352      # Returns "true" if the "transfer-encoding" header is present and
1353      # set to "chunked".  This is an HTTP/1.1 feature, allowing the 
1354      # the content to be sent in "chunks" without at the outset
1355      # stating the entire content length.
1356      def chunked?
1357        return false unless @header['transfer-encoding']
1358        field = self['Transfer-Encoding']
1359        (/(?:\A|[^\-\w])chunked(?![\-\w])/i =~ field) ? true : false
1360      end
1361 
1362      # Returns a Range object which represents Content-Range: header field.
1363      # This indicates, for a partial entity body, where this fragment
1364      # fits inside the full entity body, as range of byte offsets.
1365      def content_range
1366        return nil unless @header['content-range']
1367        m = %r<bytes\s+(\d+)-(\d+)/(\d+|\*)>i.match(self['Content-Range']) or
1368            raise HTTPHeaderSyntaxError, 'wrong Content-Range format'
1369        m[1].to_i .. m[2].to_i
1370      end
1371 
1372      # The length of the range represented in Content-Range: header.
1373      def range_length
1374        r = content_range() or return nil
1375        r.end - r.begin + 1
1376      end
1377 
1378      # Returns a content type string such as "text/html".
1379      # This method returns nil if Content-Type: header field does not exist.
1380      def content_type
1381        return nil unless main_type()
1382        if sub_type()
1383        then "#{main_type()}/#{sub_type()}"
1384        else main_type()
1385        end
1386      end
1387 
1388      # Returns a content type string such as "text".
1389      # This method returns nil if Content-Type: header field does not exist.
1390      def main_type
1391        return nil unless @header['content-type']
1392        self['Content-Type'].split(';').first.to_s.split('/')[0].to_s.strip
1393      end
1394      
1395      # Returns a content type string such as "html".
1396      # This method returns nil if Content-Type: header field does not exist
1397      # or sub-type is not given (e.g. "Content-Type: text").
1398      def sub_type
1399        return nil unless @header['content-type']
1400        main, sub = *self['Content-Type'].split(';').first.to_s.split('/')
1401        return nil unless sub
1402        sub.strip
1403      end
1404 
1405      # Returns content type parameters as a Hash as like
1406      # {"charset" => "iso-2022-jp"}.
1407      def type_params
1408        result = {}
1409        list = self['Content-Type'].to_s.split(';')
1410        list.shift
1411        list.each do |param|
1412          k, v = *param.split('=', 2)
1413          result[k.strip] = v.strip
1414        end
1415        result
1416      end
1417 
1418      # Set Content-Type: header field by +type+ and +params+.
1419      # +type+ must be a String, +params+ must be a Hash.
1420      def set_content_type(type, params = {})
1421        @header['content-type'] = [type + params.map{|k,v|"; #{k}=#{v}"}.join('')]
1422      end
1423 
1424      alias content_type= set_content_type
1425 
1426      # Set header fields and a body from HTML form data.
1427      # +params+ should be a Hash containing HTML form data.
1428      # Optional argument +sep+ means data record separator.
1429      #
1430      # This method also set Content-Type: header field to
1431      # application/x-www-form-urlencoded.
1432      def set_form_data(params, sep = '&')
1433        self.body = params.map {|k,v| "#{urlencode(k.to_s)}=#{urlencode(v.to_s)}" }.join(sep)
1434        self.content_type = 'application/x-www-form-urlencoded'
1435      end
1436 
1437      alias form_data= set_form_data
1438 
1439      def urlencode(str)
1440        str.gsub(/[^a-zA-Z0-9_\.\-]/n) {|s| sprintf('%%%02x', s[0]) }
1441      end
1442      private :urlencode
1443 
1444      # Set the Authorization: header for "Basic" authorization.
1445      def basic_auth(account, password)
1446        @header['authorization'] = [basic_encode(account, password)]
1447      end
1448 
1449      # Set Proxy-Authorization: header for "Basic" authorization.
1450      def proxy_basic_auth(account, password)
1451        @header['proxy-authorization'] = [basic_encode(account, password)]
1452      end
1453 
1454      def basic_encode(account, password)
1455        'Basic ' + ["#{account}:#{password}"].pack('m').delete("\r\n")
1456      end
1457      private :basic_encode
1458 
1459    end
1460 
1461 
1462    #
1463    # Parent of HTTPRequest class.  Do not use this directly; use
1464    # a subclass of HTTPRequest.
1465    #
1466    # Mixes in the HTTPHeader module.
1467    #
1468    class HTTPGenericRequest
1469 
1470      include HTTPHeader
1471 
1472      BUFSIZE = 16*1024
1473 
1474      def initialize(m, reqbody, resbody, path, initheader = nil)
1475        @method = m
1476        @request_has_body = reqbody
1477        @response_has_body = resbody
1478        raise ArgumentError, "HTTP request path is empty" if path.empty?
1479        @path = path
1480        initialize_http_header initheader
1481        self['Accept'] ||= '*/*'
1482        @body = nil
1483        @body_stream = nil
1484      end
1485 
1486      attr_reader :method
1487      attr_reader :path
1488 
1489      def inspect
1490        "\#<#{self.class} #{@method}>"
1491      end
1492 
1493      def request_body_permitted?
1494        @request_has_body
1495      end
1496 
1497      def response_body_permitted?
1498        @response_has_body
1499      end
1500 
1501      def body_exist?
1502        warn "Net::HTTPRequest#body_exist? is obsolete; use response_body_permitted?" if $VERBOSE
1503        response_body_permitted?
1504      end
1505 
1506      attr_reader :body
1507 
1508      def body=(str)
1509        @body = str
1510        @body_stream = nil
1511        str
1512      end
1513 
1514      attr_reader :body_stream
1515 
1516      def body_stream=(input)
1517        @body = nil
1518        @body_stream = input
1519        input
1520      end
1521 
1522      def set_body_internal(str)   #:nodoc: internal use only
1523        raise ArgumentError, "both of body argument and HTTPRequest#body set" if str and (@body or @body_stream)
1524        self.body = str if str
1525      end
1526 
1527      #
1528      # write
1529      #
1530 
1531      def exec(sock, ver, path)   #:nodoc: internal use only
1532        if @body
1533          send_request_with_body sock, ver, path, @body
1534        elsif @body_stream
1535          send_request_with_body_stream sock, ver, path, @body_stream
1536        else
1537          write_header sock, ver, path
1538        end
1539      end
1540 
1541      private
1542 
1543      def send_request_with_body(sock, ver, path, body)
1544        self.content_length = body.length
1545        delete 'Transfer-Encoding'
1546        supply_default_content_type
1547        write_header sock, ver, path
1548        sock.write body
1549      end
1550 
1551      def send_request_with_body_stream(sock, ver, path, f)
1552        unless content_length() or chunked?
1553          raise ArgumentError,
1554              "Content-Length not given and Transfer-Encoding is not `chunked'"
1555        end
1556        supply_default_content_type
1557        write_header sock, ver, path
1558        if chunked?
1559          while s = f.read(BUFSIZE)
1560            sock.write(sprintf("%x\r\n", s.length) << s << "\r\n")
1561          end
1562          sock.write "0\r\n\r\n"
1563        else
1564          while s = f.read(BUFSIZE)
1565            sock.write s
1566          end
1567        end
1568      end
1569 
1570      def supply_default_content_type
1571        return if content_type()
1572        warn 'net/http: warning: Content-Type did not set; using application/x-www-form-urlencoded' if $VERBOSE
1573        set_content_type 'application/x-www-form-urlencoded'
1574      end
1575 
1576      def write_header(sock, ver, path)
1577        buf = "#{@method} #{path} HTTP/#{ver}\r\n"
1578        each_capitalized do |k,v|
1579          buf << "#{k}: #{v}\r\n"
1580        end
1581        buf << "\r\n"
1582        sock.write buf
1583      end
1584    
1585    end
1586 
1587 
1588    # 
1589    # HTTP request class. This class wraps request header and entity path.
1590    # You *must* use its subclass, Net::HTTP::Get, Post, Head.
1591    # 
1592    class HTTPRequest < HTTPGenericRequest
1593 
1594      # Creates HTTP request object.
1595      def initialize(path, initheader = nil)
1596        super self.class::METHOD,
1597              self.class::REQUEST_HAS_BODY,
1598              self.class::RESPONSE_HAS_BODY,
1599              path, initheader
1600      end
1601    end
1602 
1603 
1604    class HTTP   # reopen
1605      #
1606      # HTTP 1.1 methods --- RFC2616
1607      #
1608 
1609      class Get < HTTPRequest
1610        METHOD = 'GET'
1611        REQUEST_HAS_BODY  = false
1612        RESPONSE_HAS_BODY = true
1613      end
1614 
1615      class Head < HTTPRequest
1616        METHOD = 'HEAD'
1617        REQUEST_HAS_BODY = false
1618        RESPONSE_HAS_BODY = false
1619      end
1620 
1621      class Post < HTTPRequest
1622        METHOD = 'POST'
1623        REQUEST_HAS_BODY = true
1624        RESPONSE_HAS_BODY = true
1625      end
1626 
1627      class Put < HTTPRequest
1628        METHOD = 'PUT'
1629        REQUEST_HAS_BODY = true
1630        RESPONSE_HAS_BODY = true
1631      end
1632 
1633      class Delete < HTTPRequest
1634        METHOD = 'DELETE'
1635        REQUEST_HAS_BODY = false
1636        RESPONSE_HAS_BODY = true
1637      end
1638 
1639      class Options < HTTPRequest
1640        METHOD = 'OPTIONS'
1641        REQUEST_HAS_BODY = false
1642        RESPONSE_HAS_BODY = false
1643      end
1644 
1645      class Trace < HTTPRequest
1646        METHOD = 'TRACE'
1647        REQUEST_HAS_BODY = false
1648        RESPONSE_HAS_BODY = true
1649      end
1650 
1651      #
1652      # WebDAV methods --- RFC2518
1653      #
1654 
1655      class Propfind < HTTPRequest
1656        METHOD = 'PROPFIND'
1657        REQUEST_HAS_BODY = true
1658        RESPONSE_HAS_BODY = true
1659      end
1660 
1661      class Proppatch < HTTPRequest
1662        METHOD = 'PROPPATCH'
1663        REQUEST_HAS_BODY = true
1664        RESPONSE_HAS_BODY = true
1665      end
1666 
1667      class Mkcol < HTTPRequest
1668        METHOD = 'MKCOL'
1669        REQUEST_HAS_BODY = true
1670        RESPONSE_HAS_BODY = true
1671      end
1672 
1673      class Copy < HTTPRequest
1674        METHOD = 'COPY'
1675        REQUEST_HAS_BODY = false
1676        RESPONSE_HAS_BODY = true
1677      end
1678 
1679      class Move < HTTPRequest
1680        METHOD = 'MOVE'
1681        REQUEST_HAS_BODY = false
1682        RESPONSE_HAS_BODY = true
1683      end
1684 
1685      class Lock < HTTPRequest
1686        METHOD = 'LOCK'
1687        REQUEST_HAS_BODY = true
1688        RESPONSE_HAS_BODY = true
1689      end
1690 
1691      class Unlock < HTTPRequest
1692        METHOD = 'UNLOCK'
1693        REQUEST_HAS_BODY = true
1694        RESPONSE_HAS_BODY = true
1695      end
1696    end
1697 
1698 
1699    ###
1700    ### Response
1701    ###
1702 
1703    # HTTP exception class.
1704    # You must use its subclasses.
1705    module HTTPExceptions
1706      def initialize(msg, res)   #:nodoc:
1707        super msg
1708        @response = res
1709      end
1710      attr_reader :response
1711      alias data response    #:nodoc: obsolete
1712    end
1713    class HTTPError < ProtocolError
1714      include HTTPExceptions
1715    end
1716    class HTTPRetriableError < ProtoRetriableError
1717      include HTTPExceptions
1718    end
1719    class HTTPServerException < ProtoServerError
1720      # We cannot use the name "HTTPServerError", it is the name of the response.
1721      include HTTPExceptions
1722    end
1723    class HTTPFatalError < ProtoFatalError
1724      include HTTPExceptions
1725    end
1726 
1727 
1728    # HTTP response class. This class wraps response header and entity.
1729    # Mixes in the HTTPHeader module, which provides access to response
1730    # header values both via hash-like methods and individual readers.
1731    # Note that each possible HTTP response code defines its own 
1732    # HTTPResponse subclass.  These are listed below.
1733    # All classes are
1734    # defined under the Net module. Indentation indicates inheritance.
1735    # 
1736    #   xxx        HTTPResponse
1737    # 
1738    #     1xx        HTTPInformation
1739    #       100        HTTPContinue    
1740    #       101        HTTPSwitchProtocol
1741    # 
1742    #     2xx        HTTPSuccess
1743    #       200        HTTPOK
1744    #       201        HTTPCreated
1745    #       202        HTTPAccepted
1746    #       203        HTTPNonAuthoritativeInformation
1747    #       204        HTTPNoContent
1748    #       205        HTTPResetContent
1749    #       206        HTTPPartialContent
1750    # 
1751    #     3xx        HTTPRedirection
1752    #       300        HTTPMultipleChoice
1753    #       301        HTTPMovedPermanently
1754    #       302        HTTPFound
1755    #       303        HTTPSeeOther
1756    #       304        HTTPNotModified
1757    #       305        HTTPUseProxy
1758    #       307        HTTPTemporaryRedirect
1759    # 
1760    #     4xx        HTTPClientError
1761    #       400        HTTPBadRequest
1762    #       401        HTTPUnauthorized
1763    #       402        HTTPPaymentRequired
1764    #       403        HTTPForbidden
1765    #       404        HTTPNotFound
1766    #       405        HTTPMethodNotAllowed
1767    #       406        HTTPNotAcceptable
1768    #       407        HTTPProxyAuthenticationRequired
1769    #       408        HTTPRequestTimeOut
1770    #       409        HTTPConflict
1771    #       410        HTTPGone
1772    #       411        HTTPLengthRequired
1773    #       412        HTTPPreconditionFailed
1774    #       413        HTTPRequestEntityTooLarge
1775    #       414        HTTPRequestURITooLong
1776    #       415        HTTPUnsupportedMediaType
1777    #       416        HTTPRequestedRangeNotSatisfiable
1778    #       417        HTTPExpectationFailed
1779    # 
1780    #     5xx        HTTPServerError
1781    #       500        HTTPInternalServerError
1782    #       501        HTTPNotImplemented
1783    #       502        HTTPBadGateway
1784    #       503        HTTPServiceUnavailable
1785    #       504        HTTPGatewayTimeOut
1786    #       505        HTTPVersionNotSupported
1787    # 
1788    #     xxx        HTTPUnknownResponse
1789    #
1790    class HTTPResponse
1791      # true if the response has body.
1792      def HTTPResponse.body_permitted?
1793        self::HAS_BODY
1794      end
1795 
1796      def HTTPResponse.exception_type   # :nodoc: internal use only
1797        self::EXCEPTION_TYPE
1798      end
1799    end   # reopened after
1800 
1801    # :stopdoc:
1802 
1803    class HTTPUnknownResponse < HTTPResponse
1804      HAS_BODY = true
1805      EXCEPTION_TYPE = HTTPError
1806    end
1807    class HTTPInformation < HTTPResponse           # 1xx
1808      HAS_BODY = false
1809      EXCEPTION_TYPE = HTTPError
1810    end
1811    class HTTPSuccess < HTTPResponse               # 2xx
1812      HAS_BODY = true
1813      EXCEPTION_TYPE = HTTPError
1814    end
1815    class HTTPRedirection < HTTPResponse           # 3xx
1816      HAS_BODY = true
1817      EXCEPTION_TYPE = HTTPRetriableError
1818    end
1819    class HTTPClientError < HTTPResponse           # 4xx
1820      HAS_BODY = true
1821      EXCEPTION_TYPE = HTTPServerException   # for backward compatibility
1822    end
1823    class HTTPServerError < HTTPResponse           # 5xx
1824      HAS_BODY = true
1825      EXCEPTION_TYPE = HTTPFatalError    # for backward compatibility
1826    end
1827 
1828    class HTTPContinue < HTTPInformation           # 100
1829      HAS_BODY = false
1830    end
1831    class HTTPSwitchProtocol < HTTPInformation     # 101
1832      HAS_BODY = false
1833    end
1834 
1835    class HTTPOK < HTTPSuccess                            # 200
1836      HAS_BODY = true
1837    end
1838    class HTTPCreated < HTTPSuccess                       # 201
1839      HAS_BODY = true
1840    end
1841    class HTTPAccepted < HTTPSuccess                      # 202
1842      HAS_BODY = true
1843    end
1844    class HTTPNonAuthoritativeInformation < HTTPSuccess   # 203
1845      HAS_BODY = true
1846    end
1847    class HTTPNoContent < HTTPSuccess                     # 204
1848      HAS_BODY = false
1849    end
1850    class HTTPResetContent < HTTPSuccess                  # 205
1851      HAS_BODY = false
1852    end
1853    class HTTPPartialContent < HTTPSuccess                # 206
1854      HAS_BODY = true
1855    end
1856 
1857    class HTTPMultipleChoice < HTTPRedirection     # 300
1858      HAS_BODY = true
1859    end
1860    class HTTPMovedPermanently < HTTPRedirection   # 301
1861      HAS_BODY = true
1862    end
1863    class HTTPFound < HTTPRedirection              # 302
1864      HAS_BODY = true
1865    end
1866    HTTPMovedTemporarily = HTTPFound
1867    class HTTPSeeOther < HTTPRedirection           # 303
1868      HAS_BODY = true
1869    end
1870    class HTTPNotModified < HTTPRedirection        # 304
1871      HAS_BODY = false
1872    end
1873    class HTTPUseProxy < HTTPRedirection           # 305
1874      HAS_BODY = false
1875    end
1876    # 306 unused
1877    class HTTPTemporaryRedirect < HTTPRedirection  # 307
1878      HAS_BODY = true
1879    end
1880 
1881    class HTTPBadRequest < HTTPClientError                    # 400
1882      HAS_BODY = true
1883    end
1884    class HTTPUnauthorized < HTTPClientError                  # 401
1885      HAS_BODY = true
1886    end
1887    class HTTPPaymentRequired < HTTPClientError               # 402
1888      HAS_BODY = true
1889    end
1890    class HTTPForbidden < HTTPClientError                     # 403
1891      HAS_BODY = true
1892    end
1893    class HTTPNotFound < HTTPClientError                      # 404
1894      HAS_BODY = true
1895    end
1896    class HTTPMethodNotAllowed < HTTPClientError              # 405
1897      HAS_BODY = true
1898    end
1899    class HTTPNotAcceptable < HTTPClientError                 # 406
1900      HAS_BODY = true
1901    end
1902    class HTTPProxyAuthenticationRequired < HTTPClientError   # 407
1903      HAS_BODY = true
1904    end
1905    class HTTPRequestTimeOut < HTTPClientError                # 408
1906      HAS_BODY = true
1907    end
1908    class HTTPConflict < HTTPClientError                      # 409
1909      HAS_BODY = true
1910    end
1911    class HTTPGone < HTTPClientError                          # 410
1912      HAS_BODY = true
1913    end
1914    class HTTPLengthRequired < HTTPClientError                # 411
1915      HAS_BODY = true
1916    end
1917    class HTTPPreconditionFailed < HTTPClientError            # 412
1918      HAS_BODY = true
1919    end
1920    class HTTPRequestEntityTooLarge < HTTPClientError         # 413
1921      HAS_BODY = true
1922    end
1923    class HTTPRequestURITooLong < HTTPClientError             # 414
1924      HAS_BODY = true
1925    end
1926    HTTPRequestURITooLarge = HTTPRequestURITooLong
1927    class HTTPUnsupportedMediaType < HTTPClientError          # 415
1928      HAS_BODY = true
1929    end
1930    class HTTPRequestedRangeNotSatisfiable < HTTPClientError  # 416
1931      HAS_BODY = true
1932    end
1933    class HTTPExpectationFailed < HTTPClientError             # 417
1934      HAS_BODY = true
1935    end
1936 
1937    class HTTPInternalServerError < HTTPServerError   # 500
1938      HAS_BODY = true
1939    end
1940    class HTTPNotImplemented < HTTPServerError        # 501
1941      HAS_BODY = true
1942    end
1943    class HTTPBadGateway < HTTPServerError            # 502
1944      HAS_BODY = true
1945    end
1946    class HTTPServiceUnavailable < HTTPServerError    # 503
1947      HAS_BODY = true
1948    end
1949    class HTTPGatewayTimeOut < HTTPServerError        # 504
1950      HAS_BODY = true
1951    end
1952    class HTTPVersionNotSupported < HTTPServerError   # 505
1953      HAS_BODY = true
1954    end
1955 
1956    # :startdoc:
1957 
1958 
1959    class HTTPResponse   # reopen
1960 
1961      CODE_CLASS_TO_OBJ = {
1962        '1' => HTTPInformation,
1963        '2' => HTTPSuccess,
1964        '3' => HTTPRedirection,
1965        '4' => HTTPClientError,
1966        '5' => HTTPServerError
1967      }
1968      CODE_TO_OBJ = {
1969        '100' => HTTPContinue,
1970        '101' => HTTPSwitchProtocol,
1971 
1972        '200' => HTTPOK,
1973        '201' => HTTPCreated,
1974        '202' => HTTPAccepted,
1975        '203' => HTTPNonAuthoritativeInformation,
1976        '204' => HTTPNoContent,
1977        '205' => HTTPResetContent,
1978        '206' => HTTPPartialContent,
1979 
1980        '300' => HTTPMultipleChoice,
1981        '301' => HTTPMovedPermanently,
1982        '302' => HTTPFound,
1983        '303' => HTTPSeeOther,
1984        '304' => HTTPNotModified,
1985        '305' => HTTPUseProxy,
1986        '307' => HTTPTemporaryRedirect,
1987 
1988        '400' => HTTPBadRequest,
1989        '401' => HTTPUnauthorized,
1990        '402' => HTTPPaymentRequired,
1991        '403' => HTTPForbidden,
1992        '404' => HTTPNotFound,
1993        '405' => HTTPMethodNotAllowed,
1994        '406' => HTTPNotAcceptable,
1995        '407' => HTTPProxyAuthenticationRequired,
1996        '408' => HTTPRequestTimeOut,
1997        '409' => HTTPConflict,
1998        '410' => HTTPGone,
1999        '411' => HTTPLengthRequired,
2000        '412' => HTTPPreconditionFailed,
2001        '413' => HTTPRequestEntityTooLarge,
2002        '414' => HTTPRequestURITooLong,
2003        '415' => HTTPUnsupportedMediaType,
2004        '416' => HTTPRequestedRangeNotSatisfiable,
2005        '417' => HTTPExpectationFailed,
2006 
2007        '500' => HTTPInternalServerError,
2008        '501' => HTTPNotImplemented,
2009        '502' => HTTPBadGateway,
2010        '503' => HTTPServiceUnavailable,
2011        '504' => HTTPGatewayTimeOut,
2012        '505' => HTTPVersionNotSupported
2013      }
2014 
2015      class << HTTPResponse
2016        def read_new(sock)   #:nodoc: internal use only
2017          httpv, code, msg = read_status_line(sock)
2018          res = response_class(code).new(httpv, code, msg)
2019          each_response_header(sock) do |k,v|
2020            res.add_field k, v
2021          end
2022          res
2023        end
2024 
2025        private
2026 
2027        def read_status_line(sock)
2028          str = sock.readline
2029          m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)\s*(.*)\z/in.match(str) or
2030            raise HTTPBadResponse, "wrong status line: #{str.dump}"
2031          m.captures
2032        end
2033 
2034        def response_class(code)
2035          CODE_TO_OBJ[code] or
2036          CODE_CLASS_TO_OBJ[code[0,1]] or
2037          HTTPUnknownResponse
2038        end
2039 
2040        def each_response_header(sock)
2041          while true
2042            line = sock.readuntil("\n", true).sub(/\s+\z/, '')
2043            break if line.empty?
2044            m = /\A([^:]+):\s*/.match(line) or
2045                raise HTTPBadResponse, 'wrong header line format'
2046            yield m[1], m.post_match
2047          end
2048        end
2049      end
2050 
2051      # next is to fix bug in RDoc, where the private inside class << self
2052      # spills out.
2053      public 
2054 
2055      include HTTPHeader
2056 
2057      def initialize(httpv, code, msg)   #:nodoc: internal use only
2058        @http_version = httpv
2059        @code         = code
2060        @message      = msg
2061        initialize_http_header nil
2062        @body = nil
2063        @read = false
2064      end
2065 
2066      # The HTTP version supported by the server.
2067      attr_reader :http_version
2068 
2069      # HTTP result code string. For example, '302'.  You can also
2070      # determine the response type by which response subclass the
2071      # response object is an instance of.
2072      attr_reader :code
2073 
2074      # HTTP result message. For example, 'Not Found'.
2075      attr_reader :message
2076      alias msg message   # :nodoc: obsolete
2077 
2078      def inspect
2079        "#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
2080      end
2081 
2082      # For backward compatibility.
2083      # To allow Net::HTTP 1.1 style assignment
2084      # e.g.
2085      #    response, body = Net::HTTP.get(....)
2086      # 
2087      def to_ary
2088        warn "net/http.rb: warning: Net::HTTP v1.1 style assignment found at #{caller(1)[0]}; use `response = http.get(...)' instead." if $VERBOSE
2089        res = self.dup
2090        class << res
2091          undef to_ary
2092        end
2093        [res, res.body]
2094      end
2095 
2096      #
2097      # response <-> exception relationship
2098      #
2099 
2100      def code_type   #:nodoc:
2101        self.class
2102      end
2103 
2104      def error!   #:nodoc:
2105        raise error_type().new(@code + ' ' + @message.dump, self)
2106      end
2107 
2108      def error_type   #:nodoc:
2109        self.class::EXCEPTION_TYPE
2110      end
2111 
2112      # Raises HTTP error if the response is not 2xx.
2113      def value
2114        error! unless self.kind_of?(HTTPSuccess)
2115      end
2116 
2117      #
2118      # header (for backward compatibility only; DO NOT USE)
2119      #
2120 
2121      def response   #:nodoc:
2122        warn "#{caller(1)[0]}: warning: HTTPResponse#response is obsolete" if $VERBOSE
2123        self
2124      end
2125 
2126      def header   #:nodoc:
2127        warn "#{caller(1)[0]}: warning: HTTPResponse#header is obsolete" if $VERBOSE
2128        self
2129      end
2130 
2131      def read_header   #:nodoc:
2132        warn "#{caller(1)[0]}: warning: HTTPResponse#read_header is obsolete" if $VERBOSE
2133        self
2134      end
2135 
2136      #
2137      # body
2138      #
2139 
2140      def reading_body(sock, reqmethodallowbody)  #:nodoc: internal use only
2141        @socket = sock
2142        @body_exist = reqmethodallowbody && self.class.body_permitted?
2143        begin
2144          yield
2145          self.body   # ensure to read body
2146        ensure
2147          @socket = nil
2148        end
2149      end
2150 
2151      # Gets entity body.  If the block given, yields it to +block+.
2152      # The body is provided in fragments, as it is read in from the socket.
2153      #
2154      # Calling this method a second or subsequent time will return the
2155      # already read string.
2156      #
2157      #   http.request_get('/index.html') {|res|
2158      #     puts res.read_body
2159      #   }
2160      #
2161      #   http.request_get('/index.html') {|res|
2162      #     p res.read_body.object_id   # 538149362
2163      #     p res.read_body.object_id   # 538149362
2164      #   }
2165      #
2166      #   # using iterator
2167      #   http.request_get('/index.html') {|res|
2168      #     res.read_body do |segment|
2169      #       print segment
2170      #     end
2171      #   }
2172      #
2173      def read_body(dest = nil, &block)
2174        if @read
2175          raise IOError, "#{self.class}\#read_body called twice" if dest or block
2176          return @body
2177        end
2178        to = procdest(dest, block)
2179        stream_check
2180        if @body_exist
2181          read_body_0 to
2182          @body = to
2183        else
2184          @body = nil
2185        end
2186        @read = true
2187 
2188        @body
2189      end
2190 
2191      # Returns the entity body.
2192      #
2193      # Calling this method a second or subsequent time will return the
2194      # already read string.
2195      #
2196      #   http.request_get('/index.html') {|res|
2197      #     puts res.body
2198      #   }
2199      #
2200      #   http.request_get('/index.html') {|res|
2201      #     p res.body.object_id   # 538149362
2202      #     p res.body.object_id   # 538149362
2203      #   }
2204      #
2205      def body
2206        read_body()
2207      end
2208 
2209      alias entity body   #:nodoc: obsolete
2210 
2211      private
2212 
2213      def read_body_0(dest)
2214        if chunked?
2215          read_chunked dest
2216          return
2217        end
2218        clen = content_length()
2219        if clen
2220          @socket.read clen, dest, true   # ignore EOF
2221          return
2222        end
2223        clen = range_length()
2224        if clen
2225          @socket.read clen, dest
2226          return
2227        end
2228        @socket.read_all dest
2229      end
2230 
2231      def read_chunked(dest)
2232        len = nil
2233        total = 0
2234        while true
2235          line = @socket.readline
2236          hexlen = line.slice(/[0-9a-fA-F]+/) or
2237              raise HTTPBadResponse, "wrong chunk size line: #{line}"
2238          len = hexlen.hex
2239          break if len == 0
2240          @socket.read len, dest; total += len
2241          @socket.read 2   # \r\n
2242        end
2243        until @socket.readline.empty?
2244          # none
2245        end
2246      end
2247 
2248      def stream_check
2249        raise IOError, 'attempt to read body out of block' if @socket.closed?
2250      end
2251 
2252      def procdest(dest, block)
2253        raise ArgumentError, 'both arg and block given for HTTP method' \
2254            if dest and block
2255        if block
2256          ReadAdapter.new(block)
2257        else
2258          dest || ''
2259        end
2260      end
2261 
2262    end
2263 
2264 
2265    # :enddoc:
2266 
2267    #--
2268    # for backward compatibility
2269    class HTTP
2270      ProxyMod = ProxyDelta
2271    end
2272    module NetPrivate
2273      HTTPRequest = ::Net::HTTPRequest
2274    end
2275 
2276    HTTPInformationCode = HTTPInformation
2277    HTTPSuccessCode     = HTTPSuccess
2278    HTTPRedirectionCode = HTTPRedirection
2279    HTTPRetriableCode   = HTTPRedirection
2280    HTTPClientErrorCode = HTTPClientError
2281    HTTPFatalErrorCode  = HTTPClientError
2282    HTTPServerErrorCode = HTTPServerError
2283    HTTPResponceReceiver = HTTPResponse
2284 
2285  end   # module Net