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