Linux premium180.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
LiteSpeed
: 162.0.209.168 | : 216.73.216.187
Cant Read [ /etc/named.conf ]
8.3.30
nortrmdp
www.github.com/MadExploits
Terminal
AUTO ROOT
Adminer
Backdoor Destroyer
Linux Exploit
Lock Shell
Lock File
Create User
CREATE RDP
PHP Mailer
BACKCONNECT
UNLOCK SHELL
HASH IDENTIFIER
CPANEL RESET
CREATE WP USER
BLACK DEFEND!
README
+ Create Folder
+ Create File
/
opt /
alt /
ruby18 /
lib64 /
ruby /
1.8 /
net /
[ HOME SHELL ]
Name
Size
Permission
Action
ftp.rb
21.56
KB
-rw-r--r--
ftptls.rb
1.22
KB
-rw-r--r--
http.rb
63.99
KB
-rw-r--r--
https.rb
4.28
KB
-rw-r--r--
imap.rb
99.96
KB
-rw-r--r--
pop.rb
25.73
KB
-rw-r--r--
protocol.rb
7.65
KB
-rw-r--r--
smtp.rb
28
KB
-rw-r--r--
telnet.rb
31.69
KB
-rw-r--r--
telnets.rb
7.82
KB
-rw-r--r--
Delete
Unzip
Zip
${this.title}
Close
Code Editor : http.rb
# # = net/http.rb # # Copyright (c) 1999-2006 Yukihiro Matsumoto # Copyright (c) 1999-2006 Minero Aoki # Copyright (c) 2001 GOTOU Yuuzou # # Written and maintained by Minero Aoki <aamine@loveruby.net>. # HTTPS support added by GOTOU Yuuzou <gotoyuzo@notwork.org>. # # This file is derived from "http-access.rb". # # Documented by Minero Aoki; converted to RDoc by William Webber. # # This program is free software. You can re-distribute and/or # modify this program under the same terms of ruby itself --- # Ruby Distribution License or GNU General Public License. # # See Net::HTTP for an overview and examples. # # NOTE: You can find Japanese version of this document here: # http://www.ruby-lang.org/ja/man/?cmd=view;name=net%2Fhttp.rb # #-- # $Id: http.rb 29865 2010-11-22 07:22:19Z shyouhei $ #++ require 'net/protocol' require 'uri' module Net #:nodoc: # :stopdoc: class HTTPBadResponse < StandardError; end class HTTPHeaderSyntaxError < StandardError; end # :startdoc: # == What Is This Library? # # This library provides your program functions to access WWW # documents via HTTP, Hyper Text Transfer Protocol version 1.1. # For details of HTTP, refer [RFC2616] # (http://www.ietf.org/rfc/rfc2616.txt). # # == Examples # # === Getting Document From WWW Server # # Example #1: Simple GET+print # # require 'net/http' # Net::HTTP.get_print 'www.example.com', '/index.html' # # Example #2: Simple GET+print by URL # # require 'net/http' # require 'uri' # Net::HTTP.get_print URI.parse('http://www.example.com/index.html') # # Example #3: More generic GET+print # # require 'net/http' # require 'uri' # # url = URI.parse('http://www.example.com/index.html') # res = Net::HTTP.start(url.host, url.port) {|http| # http.get('/index.html') # } # puts res.body # # Example #4: More generic GET+print # # require 'net/http' # # url = URI.parse('http://www.example.com/index.html') # req = Net::HTTP::Get.new(url.path) # res = Net::HTTP.start(url.host, url.port) {|http| # http.request(req) # } # puts res.body # # === Posting Form Data # # require 'net/http' # require 'uri' # # #1: Simple POST # res = Net::HTTP.post_form(URI.parse('http://www.example.com/search.cgi'), # {'q'=>'ruby', 'max'=>'50'}) # puts res.body # # #2: POST with basic authentication # res = Net::HTTP.post_form(URI.parse('http://jack:pass@www.example.com/todo.cgi'), # {'from'=>'2005-01-01', 'to'=>'2005-03-31'}) # puts res.body # # #3: Detailed control # url = URI.parse('http://www.example.com/todo.cgi') # req = Net::HTTP::Post.new(url.path) # req.basic_auth 'jack', 'pass' # req.set_form_data({'from'=>'2005-01-01', 'to'=>'2005-03-31'}, ';') # res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) } # case res # when Net::HTTPSuccess, Net::HTTPRedirection # # OK # else # res.error! # end # # === Accessing via Proxy # # Net::HTTP.Proxy creates http proxy class. It has same # methods of Net::HTTP but its instances always connect to # proxy, instead of given host. # # require 'net/http' # # proxy_addr = 'your.proxy.host' # proxy_port = 8080 # : # Net::HTTP::Proxy(proxy_addr, proxy_port).start('www.example.com') {|http| # # always connect to your.proxy.addr:8080 # : # } # # Since Net::HTTP.Proxy returns Net::HTTP itself when proxy_addr is nil, # there's no need to change code if there's proxy or not. # # There are two additional parameters in Net::HTTP.Proxy which allow to # specify proxy user name and password: # # Net::HTTP::Proxy(proxy_addr, proxy_port, proxy_user = nil, proxy_pass = nil) # # You may use them to work with authorization-enabled proxies: # # require 'net/http' # require 'uri' # # proxy_host = 'your.proxy.host' # proxy_port = 8080 # uri = URI.parse(ENV['http_proxy']) # proxy_user, proxy_pass = uri.userinfo.split(/:/) if uri.userinfo # Net::HTTP::Proxy(proxy_host, proxy_port, # proxy_user, proxy_pass).start('www.example.com') {|http| # # always connect to your.proxy.addr:8080 using specified username and password # : # } # # Note that net/http never rely on HTTP_PROXY environment variable. # If you want to use proxy, set it explicitly. # # === Following Redirection # # require 'net/http' # require 'uri' # # def fetch(uri_str, limit = 10) # # You should choose better exception. # raise ArgumentError, 'HTTP redirect too deep' if limit == 0 # # response = Net::HTTP.get_response(URI.parse(uri_str)) # case response # when Net::HTTPSuccess then response # when Net::HTTPRedirection then fetch(response['location'], limit - 1) # else # response.error! # end # end # # print fetch('http://www.ruby-lang.org') # # Net::HTTPSuccess and Net::HTTPRedirection is a HTTPResponse class. # All HTTPResponse objects belong to its own response class which # indicate HTTP result status. For details of response classes, # see section "HTTP Response Classes". # # === Basic Authentication # # require 'net/http' # # Net::HTTP.start('www.example.com') {|http| # req = Net::HTTP::Get.new('/secret-page.html') # req.basic_auth 'account', 'password' # response = http.request(req) # print response.body # } # # === HTTP Request Classes # # Here is HTTP request class hierarchy. # # Net::HTTPRequest # Net::HTTP::Get # Net::HTTP::Head # Net::HTTP::Post # Net::HTTP::Put # Net::HTTP::Proppatch # Net::HTTP::Lock # Net::HTTP::Unlock # Net::HTTP::Options # Net::HTTP::Propfind # Net::HTTP::Delete # Net::HTTP::Move # Net::HTTP::Copy # Net::HTTP::Mkcol # Net::HTTP::Trace # # === HTTP Response Classes # # Here is HTTP response class hierarchy. # All classes are defined in Net module. # # HTTPResponse # HTTPUnknownResponse # HTTPInformation # 1xx # HTTPContinue # 100 # HTTPSwitchProtocl # 101 # HTTPSuccess # 2xx # HTTPOK # 200 # HTTPCreated # 201 # HTTPAccepted # 202 # HTTPNonAuthoritativeInformation # 203 # HTTPNoContent # 204 # HTTPResetContent # 205 # HTTPPartialContent # 206 # HTTPRedirection # 3xx # HTTPMultipleChoice # 300 # HTTPMovedPermanently # 301 # HTTPFound # 302 # HTTPSeeOther # 303 # HTTPNotModified # 304 # HTTPUseProxy # 305 # HTTPTemporaryRedirect # 307 # HTTPClientError # 4xx # HTTPBadRequest # 400 # HTTPUnauthorized # 401 # HTTPPaymentRequired # 402 # HTTPForbidden # 403 # HTTPNotFound # 404 # HTTPMethodNotAllowed # 405 # HTTPNotAcceptable # 406 # HTTPProxyAuthenticationRequired # 407 # HTTPRequestTimeOut # 408 # HTTPConflict # 409 # HTTPGone # 410 # HTTPLengthRequired # 411 # HTTPPreconditionFailed # 412 # HTTPRequestEntityTooLarge # 413 # HTTPRequestURITooLong # 414 # HTTPUnsupportedMediaType # 415 # HTTPRequestedRangeNotSatisfiable # 416 # HTTPExpectationFailed # 417 # HTTPServerError # 5xx # HTTPInternalServerError # 500 # HTTPNotImplemented # 501 # HTTPBadGateway # 502 # HTTPServiceUnavailable # 503 # HTTPGatewayTimeOut # 504 # HTTPVersionNotSupported # 505 # # == Switching Net::HTTP versions # # You can use net/http.rb 1.1 features (bundled with Ruby 1.6) # by calling HTTP.version_1_1. Calling Net::HTTP.version_1_2 # allows you to use 1.2 features again. # # # example # Net::HTTP.start {|http1| ...(http1 has 1.2 features)... } # # Net::HTTP.version_1_1 # Net::HTTP.start {|http2| ...(http2 has 1.1 features)... } # # Net::HTTP.version_1_2 # Net::HTTP.start {|http3| ...(http3 has 1.2 features)... } # # This function is NOT thread-safe. # class HTTP < Protocol # :stopdoc: Revision = %q$Revision: 29865 $.split[1] HTTPVersion = '1.1' @newimpl = true # :startdoc: # Turns on net/http 1.2 (ruby 1.8) features. # Defaults to ON in ruby 1.8. # # I strongly recommend to call this method always. # # require 'net/http' # Net::HTTP.version_1_2 # def HTTP.version_1_2 @newimpl = true end # Turns on net/http 1.1 (ruby 1.6) features. # Defaults to OFF in ruby 1.8. def HTTP.version_1_1 @newimpl = false end # true if net/http is in version 1.2 mode. # Defaults to true. def HTTP.version_1_2? @newimpl end # true if net/http is in version 1.1 compatible mode. # Defaults to true. def HTTP.version_1_1? not @newimpl end class << HTTP alias is_version_1_1? version_1_1? #:nodoc: alias is_version_1_2? version_1_2? #:nodoc: end # # short cut methods # # # Get body from target and output it to +$stdout+. The # target can either be specified as (+uri+), or as # (+host+, +path+, +port+ = 80); so: # # Net::HTTP.get_print URI.parse('http://www.example.com/index.html') # # or: # # Net::HTTP.get_print 'www.example.com', '/index.html' # def HTTP.get_print(uri_or_host, path = nil, port = nil) get_response(uri_or_host, path, port) {|res| res.read_body do |chunk| $stdout.print chunk end } nil end # Send a GET request to the target and return the response # as a string. The target can either be specified as # (+uri+), or as (+host+, +path+, +port+ = 80); so: # # print Net::HTTP.get(URI.parse('http://www.example.com/index.html')) # # or: # # print Net::HTTP.get('www.example.com', '/index.html') # def HTTP.get(uri_or_host, path = nil, port = nil) get_response(uri_or_host, path, port).body end # Send a GET request to the target and return the response # as a Net::HTTPResponse object. The target can either be specified as # (+uri+), or as (+host+, +path+, +port+ = 80); so: # # res = Net::HTTP.get_response(URI.parse('http://www.example.com/index.html')) # print res.body # # or: # # res = Net::HTTP.get_response('www.example.com', '/index.html') # print res.body # def HTTP.get_response(uri_or_host, path = nil, port = nil, &block) if path host = uri_or_host new(host, port || HTTP.default_port).start {|http| return http.request_get(path, &block) } else uri = uri_or_host new(uri.host, uri.port).start {|http| return http.request_get(uri.request_uri, &block) } end end # Posts HTML form data to the +URL+. # Form data must be represented as a Hash of String to String, e.g: # # { "cmd" => "search", "q" => "ruby", "max" => "50" } # # This method also does Basic Authentication iff +URL+.user exists. # # Example: # # require 'net/http' # require 'uri' # # HTTP.post_form URI.parse('http://www.example.com/search.cgi'), # { "q" => "ruby", "max" => "50" } # def HTTP.post_form(url, params) req = Post.new(url.path) req.form_data = params req.basic_auth url.user, url.password if url.user new(url.host, url.port).start {|http| http.request(req) } end # # HTTP session management # # The default port to use for HTTP requests; defaults to 80. def HTTP.default_port http_default_port() end # The default port to use for HTTP requests; defaults to 80. def HTTP.http_default_port 80 end # The default port to use for HTTPS requests; defaults to 443. def HTTP.https_default_port 443 end def HTTP.socket_type #:nodoc: obsolete BufferedIO end # creates a new Net::HTTP object and opens its TCP connection and # HTTP session. If the optional block is given, the newly # created Net::HTTP object is passed to it and closed when the # block finishes. In this case, the return value of this method # is the return value of the block. If no block is given, the # return value of this method is the newly created Net::HTTP object # itself, and the caller is responsible for closing it upon completion. def HTTP.start(address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil, &block) # :yield: +http+ new(address, port, p_addr, p_port, p_user, p_pass).start(&block) end class << HTTP alias newobj new end # Creates a new Net::HTTP object. # If +proxy_addr+ is given, creates an Net::HTTP object with proxy support. # This method does not open the TCP connection. def HTTP.new(address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil) h = Proxy(p_addr, p_port, p_user, p_pass).newobj(address, port) h.instance_eval { @newimpl = ::Net::HTTP.version_1_2? } h end # Creates a new Net::HTTP object for the specified +address+. # This method does not open the TCP connection. def initialize(address, port = nil) @address = address @port = (port || HTTP.default_port) @curr_http_version = HTTPVersion @seems_1_0_server = false @close_on_empty_response = false @socket = nil @started = false @open_timeout = nil @read_timeout = 60 @debug_output = nil @use_ssl = false @ssl_context = nil end def inspect "#<#{self.class} #{@address}:#{@port} open=#{started?}>" end # *WARNING* This method causes serious security hole. # Never use this method in production code. # # Set an output stream for debugging. # # http = Net::HTTP.new # http.set_debug_output $stderr # http.start { .... } # def set_debug_output(output) warn 'Net::HTTP#set_debug_output called after HTTP started' if started? @debug_output = output end # The host name to connect to. attr_reader :address # The port number to connect to. attr_reader :port # Seconds to wait until connection is opened. # If the HTTP object cannot open a connection in this many seconds, # it raises a TimeoutError exception. attr_accessor :open_timeout # Seconds to wait until reading one block (by one read(2) call). # If the HTTP object cannot open a connection in this many seconds, # it raises a TimeoutError exception. attr_reader :read_timeout # Setter for the read_timeout attribute. def read_timeout=(sec) @socket.read_timeout = sec if @socket @read_timeout = sec end # returns true if the HTTP session is started. def started? @started end alias active? started? #:nodoc: obsolete attr_accessor :close_on_empty_response # returns true if use SSL/TLS with HTTP. def use_ssl? false # redefined in net/https end # Opens TCP connection and HTTP session. # # When this method is called with block, gives a HTTP object # to the block and closes the TCP connection / HTTP session # after the block executed. # # When called with a block, returns the return value of the # block; otherwise, returns self. # def start # :yield: http raise IOError, 'HTTP session already opened' if @started if block_given? begin do_start return yield(self) ensure do_finish end end do_start self end def do_start connect @started = true end private :do_start def connect D "opening connection to #{conn_address()}..." s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) } D "opened" if use_ssl? unless @ssl_context.verify_mode warn "warning: peer certificate won't be verified in this SSL session" @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE end s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context) s.sync_close = true end @socket = BufferedIO.new(s) @socket.read_timeout = @read_timeout @socket.debug_output = @debug_output if use_ssl? if proxy? @socket.writeline sprintf('CONNECT %s:%s HTTP/%s', @address, @port, HTTPVersion) @socket.writeline "Host: #{@address}:#{@port}" if proxy_user credential = ["#{proxy_user}:#{proxy_pass}"].pack('m') credential.delete!("\r\n") @socket.writeline "Proxy-Authorization: Basic #{credential}" end @socket.writeline '' HTTPResponse.read_new(@socket).value end s.connect if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE s.post_connection_check(@address) end end on_connect end private :connect def on_connect end private :on_connect # Finishes HTTP session and closes TCP connection. # Raises IOError if not started. def finish raise IOError, 'HTTP session not yet started' unless started? do_finish end def do_finish @started = false @socket.close if @socket and not @socket.closed? @socket = nil end private :do_finish # # proxy # public # no proxy @is_proxy_class = false @proxy_addr = nil @proxy_port = nil @proxy_user = nil @proxy_pass = nil # Creates an HTTP proxy class. # Arguments are address/port of proxy host and username/password # if authorization on proxy server is required. # You can replace the HTTP class with created proxy class. # # If ADDRESS is nil, this method returns self (Net::HTTP). # # # Example # proxy_class = Net::HTTP::Proxy('proxy.example.com', 8080) # : # proxy_class.start('www.ruby-lang.org') {|http| # # connecting proxy.foo.org:8080 # : # } # def HTTP.Proxy(p_addr, p_port = nil, p_user = nil, p_pass = nil) return self unless p_addr delta = ProxyDelta proxyclass = Class.new(self) proxyclass.module_eval { include delta # with proxy @is_proxy_class = true @proxy_address = p_addr @proxy_port = p_port || default_port() @proxy_user = p_user @proxy_pass = p_pass } proxyclass end class << HTTP # returns true if self is a class which was created by HTTP::Proxy. def proxy_class? @is_proxy_class end attr_reader :proxy_address attr_reader :proxy_port attr_reader :proxy_user attr_reader :proxy_pass end # True if self is a HTTP proxy class. def proxy? self.class.proxy_class? end # Address of proxy host. If self does not use a proxy, nil. def proxy_address self.class.proxy_address end # Port number of proxy host. If self does not use a proxy, nil. def proxy_port self.class.proxy_port end # User name for accessing proxy. If self does not use a proxy, nil. def proxy_user self.class.proxy_user end # User password for accessing proxy. If self does not use a proxy, nil. def proxy_pass self.class.proxy_pass end alias proxyaddr proxy_address #:nodoc: obsolete alias proxyport proxy_port #:nodoc: obsolete private # without proxy def conn_address address() end def conn_port port() end def edit_path(path) path end module ProxyDelta #:nodoc: internal use only private def conn_address proxy_address() end def conn_port proxy_port() end def edit_path(path) use_ssl? ? path : "http://#{addr_port()}#{path}" end end # # HTTP operations # public # Gets data from +path+ on the connected-to host. # +header+ must be a Hash like { 'Accept' => '*/*', ... }. # # In version 1.1 (ruby 1.6), this method returns a pair of objects, # a Net::HTTPResponse object and the entity body string. # In version 1.2 (ruby 1.8), this method returns a Net::HTTPResponse # object. # # If called with a block, yields each fragment of the # entity body in turn as a string as it is read from # the socket. Note that in this case, the returned response # object will *not* contain a (meaningful) body. # # +dest+ argument is obsolete. # It still works but you must not use it. # # In version 1.1, this method might raise an exception for # 3xx (redirect). In this case you can get a HTTPResponse object # by "anException.response". # # In version 1.2, this method never raises exception. # # # version 1.1 (bundled with Ruby 1.6) # response, body = http.get('/index.html') # # # version 1.2 (bundled with Ruby 1.8 or later) # response = http.get('/index.html') # # # using block # File.open('result.txt', 'w') {|f| # http.get('/~foo/') do |str| # f.write str # end # } # def get(path, initheader = nil, dest = nil, &block) # :yield: +body_segment+ res = nil request(Get.new(path, initheader)) {|r| r.read_body dest, &block res = r } unless @newimpl res.value return res, res.body end res end # Gets only the header from +path+ on the connected-to host. # +header+ is a Hash like { 'Accept' => '*/*', ... }. # # This method returns a Net::HTTPResponse object. # # In version 1.1, this method might raise an exception for # 3xx (redirect). On the case you can get a HTTPResponse object # by "anException.response". # In version 1.2, this method never raises an exception. # # response = nil # Net::HTTP.start('some.www.server', 80) {|http| # response = http.head('/index.html') # } # p response['content-type'] # def head(path, initheader = nil) res = request(Head.new(path, initheader)) res.value unless @newimpl res end # Posts +data+ (must be a String) to +path+. +header+ must be a Hash # like { 'Accept' => '*/*', ... }. # # In version 1.1 (ruby 1.6), this method returns a pair of objects, a # Net::HTTPResponse object and an entity body string. # In version 1.2 (ruby 1.8), this method returns a Net::HTTPResponse object. # # If called with a block, yields each fragment of the # entity body in turn as a string as it are read from # the socket. Note that in this case, the returned response # object will *not* contain a (meaningful) body. # # +dest+ argument is obsolete. # It still works but you must not use it. # # In version 1.1, this method might raise an exception for # 3xx (redirect). In this case you can get an HTTPResponse object # by "anException.response". # In version 1.2, this method never raises exception. # # # version 1.1 # response, body = http.post('/cgi-bin/search.rb', 'query=foo') # # # version 1.2 # response = http.post('/cgi-bin/search.rb', 'query=foo') # # # using block # File.open('result.txt', 'w') {|f| # http.post('/cgi-bin/search.rb', 'query=foo') do |str| # f.write str # end # } # # You should set Content-Type: header field for POST. # If no Content-Type: field given, this method uses # "application/x-www-form-urlencoded" by default. # def post(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+ res = nil request(Post.new(path, initheader), data) {|r| r.read_body dest, &block res = r } unless @newimpl res.value return res, res.body end res end def put(path, data, initheader = nil) #:nodoc: res = request(Put.new(path, initheader), data) res.value unless @newimpl res end # Sends a PROPPATCH request to the +path+ and gets a response, # as an HTTPResponse object. def proppatch(path, body, initheader = nil) request(Proppatch.new(path, initheader), body) end # Sends a LOCK request to the +path+ and gets a response, # as an HTTPResponse object. def lock(path, body, initheader = nil) request(Lock.new(path, initheader), body) end # Sends a UNLOCK request to the +path+ and gets a response, # as an HTTPResponse object. def unlock(path, body, initheader = nil) request(Unlock.new(path, initheader), body) end # Sends a OPTIONS request to the +path+ and gets a response, # as an HTTPResponse object. def options(path, initheader = nil) request(Options.new(path, initheader)) end # Sends a PROPFIND request to the +path+ and gets a response, # as an HTTPResponse object. def propfind(path, body = nil, initheader = {'Depth' => '0'}) request(Propfind.new(path, initheader), body) end # Sends a DELETE request to the +path+ and gets a response, # as an HTTPResponse object. def delete(path, initheader = {'Depth' => 'Infinity'}) request(Delete.new(path, initheader)) end # Sends a MOVE request to the +path+ and gets a response, # as an HTTPResponse object. def move(path, initheader = nil) request(Move.new(path, initheader)) end # Sends a COPY request to the +path+ and gets a response, # as an HTTPResponse object. def copy(path, initheader = nil) request(Copy.new(path, initheader)) end # Sends a MKCOL request to the +path+ and gets a response, # as an HTTPResponse object. def mkcol(path, body = nil, initheader = nil) request(Mkcol.new(path, initheader), body) end # Sends a TRACE request to the +path+ and gets a response, # as an HTTPResponse object. def trace(path, initheader = nil) request(Trace.new(path, initheader)) end # Sends a GET request to the +path+ and gets a response, # as an HTTPResponse object. # # When called with a block, yields an HTTPResponse object. # The body of this response will not have been read yet; # the caller can process it using HTTPResponse#read_body, # if desired. # # Returns the response. # # This method never raises Net::* exceptions. # # response = http.request_get('/index.html') # # The entity body is already read here. # p response['content-type'] # puts response.body # # # using block # http.request_get('/index.html') {|response| # p response['content-type'] # response.read_body do |str| # read body now # print str # end # } # def request_get(path, initheader = nil, &block) # :yield: +response+ request(Get.new(path, initheader), &block) end # Sends a HEAD request to the +path+ and gets a response, # as an HTTPResponse object. # # Returns the response. # # This method never raises Net::* exceptions. # # response = http.request_head('/index.html') # p response['content-type'] # def request_head(path, initheader = nil, &block) request(Head.new(path, initheader), &block) end # Sends a POST request to the +path+ and gets a response, # as an HTTPResponse object. # # When called with a block, yields an HTTPResponse object. # The body of this response will not have been read yet; # the caller can process it using HTTPResponse#read_body, # if desired. # # Returns the response. # # This method never raises Net::* exceptions. # # # example # response = http.request_post('/cgi-bin/nice.rb', 'datadatadata...') # p response.status # puts response.body # body is already read # # # using block # http.request_post('/cgi-bin/nice.rb', 'datadatadata...') {|response| # p response.status # p response['content-type'] # response.read_body do |str| # read body now # print str # end # } # def request_post(path, data, initheader = nil, &block) # :yield: +response+ request Post.new(path, initheader), data, &block end def request_put(path, data, initheader = nil, &block) #:nodoc: request Put.new(path, initheader), data, &block end alias get2 request_get #:nodoc: obsolete alias head2 request_head #:nodoc: obsolete alias post2 request_post #:nodoc: obsolete alias put2 request_put #:nodoc: obsolete # Sends an HTTP request to the HTTP server. # This method also sends DATA string if DATA is given. # # Returns a HTTPResponse object. # # This method never raises Net::* exceptions. # # response = http.send_request('GET', '/index.html') # puts response.body # def send_request(name, path, data = nil, header = nil) r = HTTPGenericRequest.new(name,(data ? true : false),true,path,header) request r, data end # Sends an HTTPRequest object REQUEST to the HTTP server. # This method also sends DATA string if REQUEST is a post/put request. # Giving DATA for get/head request causes ArgumentError. # # When called with a block, yields an HTTPResponse object. # The body of this response will not have been read yet; # the caller can process it using HTTPResponse#read_body, # if desired. # # Returns a HTTPResponse object. # # This method never raises Net::* exceptions. # def request(req, body = nil, &block) # :yield: +response+ unless started? start { req['connection'] ||= 'close' return request(req, body, &block) } end if proxy_user() unless use_ssl? req.proxy_basic_auth proxy_user(), proxy_pass() end end req.set_body_internal body begin begin_transport req req.exec @socket, @curr_http_version, edit_path(req.path) begin res = HTTPResponse.read_new(@socket) end while res.kind_of?(HTTPContinue) res.reading_body(@socket, req.response_body_permitted?) { yield res if block_given? } end_transport req, res rescue => exception D "Conn close because of error #{exception}" @socket.close if @socket and not @socket.closed? raise exception end res end private def begin_transport(req) if @socket.closed? connect end if @seems_1_0_server req['connection'] ||= 'close' end if not req.response_body_permitted? and @close_on_empty_response req['connection'] ||= 'close' end req['host'] ||= addr_port() end def end_transport(req, res) @curr_http_version = res.http_version if not res.body and @close_on_empty_response D 'Conn close' @socket.close elsif keep_alive?(req, res) D 'Conn keep-alive' if @socket.closed? D 'Conn (but seems 1.0 server)' @seems_1_0_server = true end else D 'Conn close' @socket.close end end def keep_alive?(req, res) return false if /close/i =~ req['connection'].to_s return false if @seems_1_0_server return true if /keep-alive/i =~ res['connection'].to_s return false if /close/i =~ res['connection'].to_s return true if /keep-alive/i =~ res['proxy-connection'].to_s return false if /close/i =~ res['proxy-connection'].to_s (@curr_http_version == '1.1') end # # utils # private def addr_port if use_ssl? address() + (port == HTTP.https_default_port ? '' : ":#{port()}") else address() + (port == HTTP.http_default_port ? '' : ":#{port()}") end end def D(msg) return unless @debug_output @debug_output << msg @debug_output << "\n" end end HTTPSession = HTTP # # Header module. # # Provides access to @header in the mixed-into class as a hash-like # object, except with case-insensitive keys. Also provides # methods for accessing commonly-used header values in a more # convenient format. # module HTTPHeader def initialize_http_header(initheader) @header = {} return unless initheader initheader.each do |key, value| warn "net/http: warning: duplicated HTTP header: #{key}" if key?(key) and $VERBOSE @header[key.downcase] = [value.strip] end end def size #:nodoc: obsolete @header.size end alias length size #:nodoc: obsolete # Returns the header field corresponding to the case-insensitive key. # For example, a key of "Content-Type" might return "text/html" def [](key) a = @header[key.downcase] or return nil a.join(', ') end # Sets the header field corresponding to the case-insensitive key. def []=(key, val) unless val @header.delete key.downcase return val end @header[key.downcase] = [val] end # [Ruby 1.8.3] # Adds header field instead of replace. # Second argument +val+ must be a String. # See also #[]=, #[] and #get_fields. # # request.add_field 'X-My-Header', 'a' # p request['X-My-Header'] #=> "a" # p request.get_fields('X-My-Header') #=> ["a"] # request.add_field 'X-My-Header', 'b' # p request['X-My-Header'] #=> "a, b" # p request.get_fields('X-My-Header') #=> ["a", "b"] # request.add_field 'X-My-Header', 'c' # p request['X-My-Header'] #=> "a, b, c" # p request.get_fields('X-My-Header') #=> ["a", "b", "c"] # def add_field(key, val) if @header.key?(key.downcase) @header[key.downcase].push val else @header[key.downcase] = [val] end end # [Ruby 1.8.3] # Returns an array of header field strings corresponding to the # case-insensitive +key+. This method allows you to get duplicated # header fields without any processing. See also #[]. # # p response.get_fields('Set-Cookie') # #=> ["session=al98axx; expires=Fri, 31-Dec-1999 23:58:23", # "query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"] # p response['Set-Cookie'] # #=> "session=al98axx; expires=Fri, 31-Dec-1999 23:58:23, query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23" # def get_fields(key) return nil unless @header[key.downcase] @header[key.downcase].dup end # Returns the header field corresponding to the case-insensitive key. # Returns the default value +args+, or the result of the block, or nil, # if there's no header field named key. See Hash#fetch def fetch(key, *args, &block) #:yield: +key+ a = @header.fetch(key.downcase, *args, &block) a.join(', ') end # Iterates for each header names and values. def each_header #:yield: +key+, +value+ @header.each do |k,va| yield k, va.join(', ') end end alias each each_header # Iterates for each header names. def each_name(&block) #:yield: +key+ @header.each_key(&block) end alias each_key each_name # Iterates for each capitalized header names. def each_capitalized_name(&block) #:yield: +key+ @header.each_key do |k| yield capitalize(k) end end # Iterates for each header values. def each_value #:yield: +value+ @header.each_value do |va| yield va.join(', ') end end # Removes a header field. def delete(key) @header.delete(key.downcase) end # true if +key+ header exists. def key?(key) @header.key?(key.downcase) end # Returns a Hash consist of header names and values. def to_hash @header.dup end # As for #each_header, except the keys are provided in capitalized form. def each_capitalized @header.each do |k,v| yield capitalize(k), v.join(', ') end end alias canonical_each each_capitalized def capitalize(name) name.split(/-/).map {|s| s.capitalize }.join('-') end private :capitalize # Returns an Array of Range objects which represents Range: header field, # or +nil+ if there is no such header. def range return nil unless @header['range'] self['Range'].split(/,/).map {|spec| m = /bytes\s*=\s*(\d+)?\s*-\s*(\d+)?/i.match(spec) or raise HTTPHeaderSyntaxError, "wrong Range: #{spec}" d1 = m[1].to_i d2 = m[2].to_i if m[1] and m[2] then d1..d2 elsif m[1] then d1..-1 elsif m[2] then -d2..-1 else raise HTTPHeaderSyntaxError, 'range is not specified' end } end # Set Range: header from Range (arg r) or beginning index and # length from it (arg idx&len). # # req.range = (0..1023) # req.set_range 0, 1023 # def set_range(r, e = nil) unless r @header.delete 'range' return r end r = (r...r+e) if e case r when Numeric n = r.to_i rangestr = (n > 0 ? "0-#{n-1}" : "-#{-n}") when Range first = r.first last = r.last last -= 1 if r.exclude_end? if last == -1 rangestr = (first > 0 ? "#{first}-" : "-#{-first}") else raise HTTPHeaderSyntaxError, 'range.first is negative' if first < 0 raise HTTPHeaderSyntaxError, 'range.last is negative' if last < 0 raise HTTPHeaderSyntaxError, 'must be .first < .last' if first > last rangestr = "#{first}-#{last}" end else raise TypeError, 'Range/Integer is required' end @header['range'] = ["bytes=#{rangestr}"] r end alias range= set_range # Returns an Integer object which represents the Content-Length: header field # or +nil+ if that field is not provided. def content_length return nil unless key?('Content-Length') len = self['Content-Length'].slice(/\d+/) or raise HTTPHeaderSyntaxError, 'wrong Content-Length format' len.to_i end def content_length=(len) unless len @header.delete 'content-length' return nil end @header['content-length'] = [len.to_i.to_s] end # Returns "true" if the "transfer-encoding" header is present and # set to "chunked". This is an HTTP/1.1 feature, allowing the # the content to be sent in "chunks" without at the outset # stating the entire content length. def chunked? return false unless @header['transfer-encoding'] field = self['Transfer-Encoding'] (/(?:\A|[^\-\w])chunked(?![\-\w])/i =~ field) ? true : false end # Returns a Range object which represents Content-Range: header field. # This indicates, for a partial entity body, where this fragment # fits inside the full entity body, as range of byte offsets. def content_range return nil unless @header['content-range'] m = %r<bytes\s+(\d+)-(\d+)/(\d+|\*)>i.match(self['Content-Range']) or raise HTTPHeaderSyntaxError, 'wrong Content-Range format' m[1].to_i .. m[2].to_i end # The length of the range represented in Content-Range: header. def range_length r = content_range() or return nil r.end - r.begin + 1 end # Returns a content type string such as "text/html". # This method returns nil if Content-Type: header field does not exist. def content_type return nil unless main_type() if sub_type() then "#{main_type()}/#{sub_type()}" else main_type() end end # Returns a content type string such as "text". # This method returns nil if Content-Type: header field does not exist. def main_type return nil unless @header['content-type'] self['Content-Type'].split(';').first.to_s.split('/')[0].to_s.strip end # Returns a content type string such as "html". # This method returns nil if Content-Type: header field does not exist # or sub-type is not given (e.g. "Content-Type: text"). def sub_type return nil unless @header['content-type'] main, sub = *self['Content-Type'].split(';').first.to_s.split('/') return nil unless sub sub.strip end # Returns content type parameters as a Hash as like # {"charset" => "iso-2022-jp"}. def type_params result = {} list = self['Content-Type'].to_s.split(';') list.shift list.each do |param| k, v = *param.split('=', 2) result[k.strip] = v.strip end result end # Set Content-Type: header field by +type+ and +params+. # +type+ must be a String, +params+ must be a Hash. def set_content_type(type, params = {}) @header['content-type'] = [type + params.map{|k,v|"; #{k}=#{v}"}.join('')] end alias content_type= set_content_type # Set header fields and a body from HTML form data. # +params+ should be a Hash containing HTML form data. # Optional argument +sep+ means data record separator. # # This method also set Content-Type: header field to # application/x-www-form-urlencoded. def set_form_data(params, sep = '&') self.body = params.map {|k,v| "#{urlencode(k.to_s)}=#{urlencode(v.to_s)}" }.join(sep) self.content_type = 'application/x-www-form-urlencoded' end alias form_data= set_form_data def urlencode(str) str.gsub(/[^a-zA-Z0-9_\.\-]/n) {|s| sprintf('%%%02x', s[0]) } end private :urlencode # Set the Authorization: header for "Basic" authorization. def basic_auth(account, password) @header['authorization'] = [basic_encode(account, password)] end # Set Proxy-Authorization: header for "Basic" authorization. def proxy_basic_auth(account, password) @header['proxy-authorization'] = [basic_encode(account, password)] end def basic_encode(account, password) 'Basic ' + ["#{account}:#{password}"].pack('m').delete("\r\n") end private :basic_encode end # # Parent of HTTPRequest class. Do not use this directly; use # a subclass of HTTPRequest. # # Mixes in the HTTPHeader module. # class HTTPGenericRequest include HTTPHeader BUFSIZE = 16*1024 def initialize(m, reqbody, resbody, path, initheader = nil) @method = m @request_has_body = reqbody @response_has_body = resbody raise ArgumentError, "HTTP request path is empty" if path.empty? @path = path initialize_http_header initheader self['Accept'] ||= '*/*' @body = nil @body_stream = nil end attr_reader :method attr_reader :path def inspect "\#<#{self.class} #{@method}>" end def request_body_permitted? @request_has_body end def response_body_permitted? @response_has_body end def body_exist? warn "Net::HTTPRequest#body_exist? is obsolete; use response_body_permitted?" if $VERBOSE response_body_permitted? end attr_reader :body def body=(str) @body = str @body_stream = nil str end attr_reader :body_stream def body_stream=(input) @body = nil @body_stream = input input end def set_body_internal(str) #:nodoc: internal use only raise ArgumentError, "both of body argument and HTTPRequest#body set" if str and (@body or @body_stream) self.body = str if str end # # write # def exec(sock, ver, path) #:nodoc: internal use only if @body send_request_with_body sock, ver, path, @body elsif @body_stream send_request_with_body_stream sock, ver, path, @body_stream else write_header sock, ver, path end end private def send_request_with_body(sock, ver, path, body) self.content_length = body.length delete 'Transfer-Encoding' supply_default_content_type write_header sock, ver, path sock.write body end def send_request_with_body_stream(sock, ver, path, f) unless content_length() or chunked? raise ArgumentError, "Content-Length not given and Transfer-Encoding is not `chunked'" end supply_default_content_type write_header sock, ver, path if chunked? while s = f.read(BUFSIZE) sock.write(sprintf("%x\r\n", s.length) << s << "\r\n") end sock.write "0\r\n\r\n" else while s = f.read(BUFSIZE) sock.write s end end end def supply_default_content_type return if content_type() warn 'net/http: warning: Content-Type did not set; using application/x-www-form-urlencoded' if $VERBOSE set_content_type 'application/x-www-form-urlencoded' end def write_header(sock, ver, path) buf = "#{@method} #{path} HTTP/#{ver}\r\n" each_capitalized do |k,v| buf << "#{k}: #{v}\r\n" end buf << "\r\n" sock.write buf end end # # HTTP request class. This class wraps request header and entity path. # You *must* use its subclass, Net::HTTP::Get, Post, Head. # class HTTPRequest < HTTPGenericRequest # Creates HTTP request object. def initialize(path, initheader = nil) super self.class::METHOD, self.class::REQUEST_HAS_BODY, self.class::RESPONSE_HAS_BODY, path, initheader end end class HTTP # reopen # # HTTP 1.1 methods --- RFC2616 # class Get < HTTPRequest METHOD = 'GET' REQUEST_HAS_BODY = false RESPONSE_HAS_BODY = true end class Head < HTTPRequest METHOD = 'HEAD' REQUEST_HAS_BODY = false RESPONSE_HAS_BODY = false end class Post < HTTPRequest METHOD = 'POST' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end class Put < HTTPRequest METHOD = 'PUT' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end class Delete < HTTPRequest METHOD = 'DELETE' REQUEST_HAS_BODY = false RESPONSE_HAS_BODY = true end class Options < HTTPRequest METHOD = 'OPTIONS' REQUEST_HAS_BODY = false RESPONSE_HAS_BODY = false end class Trace < HTTPRequest METHOD = 'TRACE' REQUEST_HAS_BODY = false RESPONSE_HAS_BODY = true end # # WebDAV methods --- RFC2518 # class Propfind < HTTPRequest METHOD = 'PROPFIND' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end class Proppatch < HTTPRequest METHOD = 'PROPPATCH' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end class Mkcol < HTTPRequest METHOD = 'MKCOL' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end class Copy < HTTPRequest METHOD = 'COPY' REQUEST_HAS_BODY = false RESPONSE_HAS_BODY = true end class Move < HTTPRequest METHOD = 'MOVE' REQUEST_HAS_BODY = false RESPONSE_HAS_BODY = true end class Lock < HTTPRequest METHOD = 'LOCK' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end class Unlock < HTTPRequest METHOD = 'UNLOCK' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end end ### ### Response ### # HTTP exception class. # You must use its subclasses. module HTTPExceptions def initialize(msg, res) #:nodoc: super msg @response = res end attr_reader :response alias data response #:nodoc: obsolete end class HTTPError < ProtocolError include HTTPExceptions end class HTTPRetriableError < ProtoRetriableError include HTTPExceptions end class HTTPServerException < ProtoServerError # We cannot use the name "HTTPServerError", it is the name of the response. include HTTPExceptions end class HTTPFatalError < ProtoFatalError include HTTPExceptions end # HTTP response class. This class wraps response header and entity. # Mixes in the HTTPHeader module, which provides access to response # header values both via hash-like methods and individual readers. # Note that each possible HTTP response code defines its own # HTTPResponse subclass. These are listed below. # All classes are # defined under the Net module. Indentation indicates inheritance. # # xxx HTTPResponse # # 1xx HTTPInformation # 100 HTTPContinue # 101 HTTPSwitchProtocol # # 2xx HTTPSuccess # 200 HTTPOK # 201 HTTPCreated # 202 HTTPAccepted # 203 HTTPNonAuthoritativeInformation # 204 HTTPNoContent # 205 HTTPResetContent # 206 HTTPPartialContent # # 3xx HTTPRedirection # 300 HTTPMultipleChoice # 301 HTTPMovedPermanently # 302 HTTPFound # 303 HTTPSeeOther # 304 HTTPNotModified # 305 HTTPUseProxy # 307 HTTPTemporaryRedirect # # 4xx HTTPClientError # 400 HTTPBadRequest # 401 HTTPUnauthorized # 402 HTTPPaymentRequired # 403 HTTPForbidden # 404 HTTPNotFound # 405 HTTPMethodNotAllowed # 406 HTTPNotAcceptable # 407 HTTPProxyAuthenticationRequired # 408 HTTPRequestTimeOut # 409 HTTPConflict # 410 HTTPGone # 411 HTTPLengthRequired # 412 HTTPPreconditionFailed # 413 HTTPRequestEntityTooLarge # 414 HTTPRequestURITooLong # 415 HTTPUnsupportedMediaType # 416 HTTPRequestedRangeNotSatisfiable # 417 HTTPExpectationFailed # # 5xx HTTPServerError # 500 HTTPInternalServerError # 501 HTTPNotImplemented # 502 HTTPBadGateway # 503 HTTPServiceUnavailable # 504 HTTPGatewayTimeOut # 505 HTTPVersionNotSupported # # xxx HTTPUnknownResponse # class HTTPResponse # true if the response has body. def HTTPResponse.body_permitted? self::HAS_BODY end def HTTPResponse.exception_type # :nodoc: internal use only self::EXCEPTION_TYPE end end # reopened after # :stopdoc: class HTTPUnknownResponse < HTTPResponse HAS_BODY = true EXCEPTION_TYPE = HTTPError end class HTTPInformation < HTTPResponse # 1xx HAS_BODY = false EXCEPTION_TYPE = HTTPError end class HTTPSuccess < HTTPResponse # 2xx HAS_BODY = true EXCEPTION_TYPE = HTTPError end class HTTPRedirection < HTTPResponse # 3xx HAS_BODY = true EXCEPTION_TYPE = HTTPRetriableError end class HTTPClientError < HTTPResponse # 4xx HAS_BODY = true EXCEPTION_TYPE = HTTPServerException # for backward compatibility end class HTTPServerError < HTTPResponse # 5xx HAS_BODY = true EXCEPTION_TYPE = HTTPFatalError # for backward compatibility end class HTTPContinue < HTTPInformation # 100 HAS_BODY = false end class HTTPSwitchProtocol < HTTPInformation # 101 HAS_BODY = false end class HTTPOK < HTTPSuccess # 200 HAS_BODY = true end class HTTPCreated < HTTPSuccess # 201 HAS_BODY = true end class HTTPAccepted < HTTPSuccess # 202 HAS_BODY = true end class HTTPNonAuthoritativeInformation < HTTPSuccess # 203 HAS_BODY = true end class HTTPNoContent < HTTPSuccess # 204 HAS_BODY = false end class HTTPResetContent < HTTPSuccess # 205 HAS_BODY = false end class HTTPPartialContent < HTTPSuccess # 206 HAS_BODY = true end class HTTPMultipleChoice < HTTPRedirection # 300 HAS_BODY = true end class HTTPMovedPermanently < HTTPRedirection # 301 HAS_BODY = true end class HTTPFound < HTTPRedirection # 302 HAS_BODY = true end HTTPMovedTemporarily = HTTPFound class HTTPSeeOther < HTTPRedirection # 303 HAS_BODY = true end class HTTPNotModified < HTTPRedirection # 304 HAS_BODY = false end class HTTPUseProxy < HTTPRedirection # 305 HAS_BODY = false end # 306 unused class HTTPTemporaryRedirect < HTTPRedirection # 307 HAS_BODY = true end class HTTPBadRequest < HTTPClientError # 400 HAS_BODY = true end class HTTPUnauthorized < HTTPClientError # 401 HAS_BODY = true end class HTTPPaymentRequired < HTTPClientError # 402 HAS_BODY = true end class HTTPForbidden < HTTPClientError # 403 HAS_BODY = true end class HTTPNotFound < HTTPClientError # 404 HAS_BODY = true end class HTTPMethodNotAllowed < HTTPClientError # 405 HAS_BODY = true end class HTTPNotAcceptable < HTTPClientError # 406 HAS_BODY = true end class HTTPProxyAuthenticationRequired < HTTPClientError # 407 HAS_BODY = true end class HTTPRequestTimeOut < HTTPClientError # 408 HAS_BODY = true end class HTTPConflict < HTTPClientError # 409 HAS_BODY = true end class HTTPGone < HTTPClientError # 410 HAS_BODY = true end class HTTPLengthRequired < HTTPClientError # 411 HAS_BODY = true end class HTTPPreconditionFailed < HTTPClientError # 412 HAS_BODY = true end class HTTPRequestEntityTooLarge < HTTPClientError # 413 HAS_BODY = true end class HTTPRequestURITooLong < HTTPClientError # 414 HAS_BODY = true end HTTPRequestURITooLarge = HTTPRequestURITooLong class HTTPUnsupportedMediaType < HTTPClientError # 415 HAS_BODY = true end class HTTPRequestedRangeNotSatisfiable < HTTPClientError # 416 HAS_BODY = true end class HTTPExpectationFailed < HTTPClientError # 417 HAS_BODY = true end class HTTPInternalServerError < HTTPServerError # 500 HAS_BODY = true end class HTTPNotImplemented < HTTPServerError # 501 HAS_BODY = true end class HTTPBadGateway < HTTPServerError # 502 HAS_BODY = true end class HTTPServiceUnavailable < HTTPServerError # 503 HAS_BODY = true end class HTTPGatewayTimeOut < HTTPServerError # 504 HAS_BODY = true end class HTTPVersionNotSupported < HTTPServerError # 505 HAS_BODY = true end # :startdoc: class HTTPResponse # reopen CODE_CLASS_TO_OBJ = { '1' => HTTPInformation, '2' => HTTPSuccess, '3' => HTTPRedirection, '4' => HTTPClientError, '5' => HTTPServerError } CODE_TO_OBJ = { '100' => HTTPContinue, '101' => HTTPSwitchProtocol, '200' => HTTPOK, '201' => HTTPCreated, '202' => HTTPAccepted, '203' => HTTPNonAuthoritativeInformation, '204' => HTTPNoContent, '205' => HTTPResetContent, '206' => HTTPPartialContent, '300' => HTTPMultipleChoice, '301' => HTTPMovedPermanently, '302' => HTTPFound, '303' => HTTPSeeOther, '304' => HTTPNotModified, '305' => HTTPUseProxy, '307' => HTTPTemporaryRedirect, '400' => HTTPBadRequest, '401' => HTTPUnauthorized, '402' => HTTPPaymentRequired, '403' => HTTPForbidden, '404' => HTTPNotFound, '405' => HTTPMethodNotAllowed, '406' => HTTPNotAcceptable, '407' => HTTPProxyAuthenticationRequired, '408' => HTTPRequestTimeOut, '409' => HTTPConflict, '410' => HTTPGone, '411' => HTTPLengthRequired, '412' => HTTPPreconditionFailed, '413' => HTTPRequestEntityTooLarge, '414' => HTTPRequestURITooLong, '415' => HTTPUnsupportedMediaType, '416' => HTTPRequestedRangeNotSatisfiable, '417' => HTTPExpectationFailed, '500' => HTTPInternalServerError, '501' => HTTPNotImplemented, '502' => HTTPBadGateway, '503' => HTTPServiceUnavailable, '504' => HTTPGatewayTimeOut, '505' => HTTPVersionNotSupported } class << HTTPResponse def read_new(sock) #:nodoc: internal use only httpv, code, msg = read_status_line(sock) res = response_class(code).new(httpv, code, msg) each_response_header(sock) do |k,v| res.add_field k, v end res end private def read_status_line(sock) str = sock.readline m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)\s*(.*)\z/in.match(str) or raise HTTPBadResponse, "wrong status line: #{str.dump}" m.captures end def response_class(code) CODE_TO_OBJ[code] or CODE_CLASS_TO_OBJ[code[0,1]] or HTTPUnknownResponse end def each_response_header(sock) while true line = sock.readuntil("\n", true).sub(/\s+\z/, '') break if line.empty? m = /\A([^:]+):\s*/.match(line) or raise HTTPBadResponse, 'wrong header line format' yield m[1], m.post_match end end end # next is to fix bug in RDoc, where the private inside class << self # spills out. public include HTTPHeader def initialize(httpv, code, msg) #:nodoc: internal use only @http_version = httpv @code = code @message = msg initialize_http_header nil @body = nil @read = false end # The HTTP version supported by the server. attr_reader :http_version # HTTP result code string. For example, '302'. You can also # determine the response type by which response subclass the # response object is an instance of. attr_reader :code # HTTP result message. For example, 'Not Found'. attr_reader :message alias msg message # :nodoc: obsolete def inspect "#<#{self.class} #{@code} #{@message} readbody=#{@read}>" end # For backward compatibility. # To allow Net::HTTP 1.1 style assignment # e.g. # response, body = Net::HTTP.get(....) # def to_ary warn "net/http.rb: warning: Net::HTTP v1.1 style assignment found at #{caller(1)[0]}; use `response = http.get(...)' instead." if $VERBOSE res = self.dup class << res undef to_ary end [res, res.body] end # # response <-> exception relationship # def code_type #:nodoc: self.class end def error! #:nodoc: raise error_type().new(@code + ' ' + @message.dump, self) end def error_type #:nodoc: self.class::EXCEPTION_TYPE end # Raises HTTP error if the response is not 2xx. def value error! unless self.kind_of?(HTTPSuccess) end # # header (for backward compatibility only; DO NOT USE) # def response #:nodoc: warn "#{caller(1)[0]}: warning: HTTPResponse#response is obsolete" if $VERBOSE self end def header #:nodoc: warn "#{caller(1)[0]}: warning: HTTPResponse#header is obsolete" if $VERBOSE self end def read_header #:nodoc: warn "#{caller(1)[0]}: warning: HTTPResponse#read_header is obsolete" if $VERBOSE self end # # body # def reading_body(sock, reqmethodallowbody) #:nodoc: internal use only @socket = sock @body_exist = reqmethodallowbody && self.class.body_permitted? begin yield self.body # ensure to read body ensure @socket = nil end end # Gets entity body. If the block given, yields it to +block+. # The body is provided in fragments, as it is read in from the socket. # # Calling this method a second or subsequent time will return the # already read string. # # http.request_get('/index.html') {|res| # puts res.read_body # } # # http.request_get('/index.html') {|res| # p res.read_body.object_id # 538149362 # p res.read_body.object_id # 538149362 # } # # # using iterator # http.request_get('/index.html') {|res| # res.read_body do |segment| # print segment # end # } # def read_body(dest = nil, &block) if @read raise IOError, "#{self.class}\#read_body called twice" if dest or block return @body end to = procdest(dest, block) stream_check if @body_exist read_body_0 to @body = to else @body = nil end @read = true @body end # Returns the entity body. # # Calling this method a second or subsequent time will return the # already read string. # # http.request_get('/index.html') {|res| # puts res.body # } # # http.request_get('/index.html') {|res| # p res.body.object_id # 538149362 # p res.body.object_id # 538149362 # } # def body read_body() end alias entity body #:nodoc: obsolete private def read_body_0(dest) if chunked? read_chunked dest return end clen = content_length() if clen @socket.read clen, dest, true # ignore EOF return end clen = range_length() if clen @socket.read clen, dest return end @socket.read_all dest end def read_chunked(dest) len = nil total = 0 while true line = @socket.readline hexlen = line.slice(/[0-9a-fA-F]+/) or raise HTTPBadResponse, "wrong chunk size line: #{line}" len = hexlen.hex break if len == 0 @socket.read len, dest; total += len @socket.read 2 # \r\n end until @socket.readline.empty? # none end end def stream_check raise IOError, 'attempt to read body out of block' if @socket.closed? end def procdest(dest, block) raise ArgumentError, 'both arg and block given for HTTP method' \ if dest and block if block ReadAdapter.new(block) else dest || '' end end end # :enddoc: #-- # for backward compatibility class HTTP ProxyMod = ProxyDelta end module NetPrivate HTTPRequest = ::Net::HTTPRequest end HTTPInformationCode = HTTPInformation HTTPSuccessCode = HTTPSuccess HTTPRedirectionCode = HTTPRedirection HTTPRetriableCode = HTTPRedirection HTTPClientErrorCode = HTTPClientError HTTPFatalErrorCode = HTTPClientError HTTPServerErrorCode = HTTPServerError HTTPResponceReceiver = HTTPResponse end # module Net
Close