* lib/net/http.rb: HTTP.get accepts URI.

* lib/net/http.rb: add some HTTP 1.1 response codes.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2290 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
aamine 2002-03-26 11:18:02 +00:00
parent 04168e7e3e
commit 1ea1fbe85d
3 changed files with 294 additions and 193 deletions

View File

@ -1,3 +1,9 @@
Tue Mar 26 20:28:50 2002 Minero Aoki <aamine@loveruby.net>
* lib/net/http.rb: HTTP.get accepts URI.
* lib/net/http.rb: add some HTTP 1.1 response codes.
Tue Mar 26 20:25:28 2002 Minero Aoki <aamine@loveruby.net> Tue Mar 26 20:25:28 2002 Minero Aoki <aamine@loveruby.net>
* doc/net/protocol.rd.ja, smtp.rd.ja, pop.rd.ja: removed. * doc/net/protocol.rd.ja, smtp.rd.ja, pop.rd.ja: removed.

View File

@ -27,13 +27,10 @@ For details of HTTP, refer [RFC2616]
=== Getting Document From Server === Getting Document From Server
Be care to ',' (comma) putted after "response".
This is required for compatibility.
require 'net/http' require 'net/http'
Net::HTTP.start( 'some.www.server', 80 ) {|http| Net::HTTP.start( 'some.www.server', 80 ) {|http|
response , = http.get('/index.html') response = http.get('/index.html')
puts response.body puts response.body
} }
(shorter version) (shorter version)
@ -45,8 +42,8 @@ This is required for compatibility.
require 'net/http' require 'net/http'
Net::HTTP.start( 'some.www.server', 80 ) {|http| Net::HTTP.start( 'some.www.server', 80 ) {|http|
response , = http.post( '/cgi-bin/any.rhtml', response = http.post( '/cgi-bin/any.rhtml',
'querytype=subject&target=ruby' ) 'querytype=subject&target=ruby' )
} }
=== Accessing via Proxy === Accessing via Proxy
@ -71,40 +68,29 @@ there's no need to change code if there's proxy or not.
=== Redirect === Redirect
require 'net/http' require 'net/http'
Net::HTTP.version_1_1 require 'uri'
host = 'www.ruby-lang.org' def read_uri( uri )
path = '/' response = HTTP.get_uri(URI.parse(uri))
begin case response
Net::HTTP.start( host, 80 ) {|http| when Net::HTTPSuccess then response
response , = http.get(path) when Net::HTTPRedirection then read_uri(response['location'])
print response.body else
} response.error!
rescue Net::ProtoRetriableError => err
if m = %r<http://([^/]+)>.match( err.response['location'] ) then
host = m[1].strip
path = m.post_match
retry
end end
end end
NOTE: This code is using ad-hoc way to extract host name, but in future p read_uri('http://www.ruby-lang.org')
URI class will be included in ruby standard library.
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 === Basic Authentication
require 'net/http' require 'net/http'
Net::HTTP.start( 'auth.some.domain' ) {|http|
response , = http.get( '/need-auth.cgi',
'Authorization' => 'Basic ' + ["#{account}:#{password}"].pack('m').strip )
print response.body
}
In version 1.2 (Ruby 1.7 or later), you can write like this:
require 'net/http'
req = Net::HTTP::Get.new('/need-auth.cgi') req = Net::HTTP::Get.new('/need-auth.cgi')
req.basic_auth 'account', 'password' req.basic_auth 'account', 'password'
Net::HTTP.start( 'auth.some.domain' ) {|http| Net::HTTP.start( 'auth.some.domain' ) {|http|
@ -112,11 +98,70 @@ In version 1.2 (Ruby 1.7 or later), you can write like this:
print response.body print response.body
} }
=== HTTP Response Classes
Followings are sub classes of Net::HTTPResponse. 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
== Switching Net::HTTP versions == Switching Net::HTTP versions
You can use old Net::HTTP (in Ruby 1.6) features by calling You can use net/http.rb 1.1 features (bundled with Ruby 1.6)
HTTP.version_1_1. And calling Net::HTTP.version_1_2 allows by calling HTTP.version_1_1. Calling Net::HTTP.version_1_2
you to use 1.2 features again. allows you to use 1.2 features again.
# example # example
Net::HTTP.start {|http1| ...(http1 has 1.2 features)... } Net::HTTP.start {|http1| ...(http1 has 1.2 features)... }
@ -127,7 +172,7 @@ you to use 1.2 features again.
Net::HTTP.version_1_2 Net::HTTP.version_1_2
Net::HTTP.start {|http3| ...(http3 has 1.2 features)... } Net::HTTP.start {|http3| ...(http3 has 1.2 features)... }
Yes, this is not thread-safe. This function is not thread-safe.
== class Net::HTTP == class Net::HTTP
@ -138,10 +183,14 @@ Yes, this is not thread-safe.
If proxy_addr is given, creates an Net::HTTP object with proxy support. If proxy_addr is given, creates an Net::HTTP object with proxy support.
: start( address, port = 80, proxy_addr = nil, proxy_port = nil ) : start( address, port = 80, proxy_addr = nil, proxy_port = nil )
: start( address, port = 80, proxy_addr = nil, proxy_port = nil ) {|http| .... } creates a new Net::HTTP object and returns it
is equals to with opening HTTP session.
Net::HTTP.new(address, port, proxy_addr, proxy_port).start(&block) : start( address, port = 80, proxy_addr = nil, proxy_port = nil ) {|http| .... }
creates a new Net::HTTP object and gives it to the block.
HTTP session is kept to open while the block is exected.
This method returns the return value of the block.
: get( address, path, port = 80 ) : get( address, path, port = 80 )
gets entity body from path and returns it. gets entity body from path and returns it.
@ -176,13 +225,13 @@ Yes, this is not thread-safe.
: start : start
: start {|http| .... } : start {|http| .... }
creates a new Net::HTTP object and starts HTTP session. opens HTTP session.
When this method is called with block, gives a HTTP object to block When this method is called with block, gives a HTTP object
and close the HTTP session after block call finished. to the block and closes the HTTP session after block call finished.
: active? : started?
true if HTTP session is started. returns true if HTTP session is started.
: address : address
the address to connect the address to connect
@ -342,7 +391,7 @@ Yes, this is not thread-safe.
p response['content-type'] p response['content-type']
response.read_body do |str| # read body now response.read_body do |str| # read body now
print str print str
end end
} }
: request( request [, data] ) : request( request [, data] )
@ -356,10 +405,10 @@ Yes, this is not thread-safe.
This method never raises Net::* exceptions. This method never raises Net::* exceptions.
== class Net::HTTP::Get, Head, Post == class Net::HTTPRequest
HTTP request classes. These classes wraps request header and HTTP request class. This class wraps request header and entity path.
entity path. All arguments named "key" is case-insensitive. You MUST use its subclass, Net::HTTP::Get, Post, Head.
=== Class Methods === Class Methods
@ -485,22 +534,34 @@ module Net
# short cut methods # short cut methods
# #
def HTTP.get( addr, path, port = nil )
req = Get.new( path )
resp = nil
new( addr, port || HTTP.default_port ).start {|http|
resp = http.request( req )
}
resp.body
end
def HTTP.get_print( addr, path, port = nil ) def HTTP.get_print( addr, path, port = nil )
new( addr, port || HTTP.port ).start {|http| new( addr, port || HTTP.default_port ).start {|http|
http.get path, nil, $stdout http.get path, nil, $stdout
} }
nil nil
end end
def HTTP.get( arg1, arg2 = nil, arg3 = nil )
if arg2 then
get_path(arg1, arg2, arg3).body
else
get_uri(arg1).body
end
end
def HTTP.get_path( addr, path, port = nil )
new( addr, port || HTTP.default_port ).start {|http|
return http.request(Get.new(path))
}
end
private_class_method :get_path
def HTTP.get_uri( uri )
new(uri.addr, uri.port).start {|http|
return http.request(Get.new(http_path(uri)))
}
end
# #
# connection # connection
@ -527,8 +588,11 @@ module Net
super super
@curr_http_version = HTTPVersion @curr_http_version = HTTPVersion
@seems_1_0_server = false @seems_1_0_server = false
@close_on_empty_response = false
end end
attr_accessor :close_on_empty_response
private private
def do_start def do_start
@ -577,15 +641,15 @@ module Net
end end
def proxy? def proxy?
type.proxy_class? self.class.proxy_class?
end end
def proxy_address def proxy_address
type.proxy_address self.class.proxy_address
end end
def proxy_port def proxy_port
type.proxy_port self.class.proxy_port
end end
alias proxyaddr proxy_address alias proxyaddr proxy_address
@ -701,7 +765,7 @@ module Net
def request( req, body = nil, &block ) def request( req, body = nil, &block )
unless active? then unless started? then
start { start {
req['connection'] = 'close' req['connection'] = 'close'
return request(req, body, &block) return request(req, body, &block)
@ -709,12 +773,13 @@ module Net
end end
begin_transport req begin_transport req
req.__send__(:exec, req.exec @socket, @curr_http_version, edit_path(req.path), body
@socket, @curr_http_version, edit_path(req.path), body)
begin begin
res = HTTPResponse.read_new(@socket, req.response_body_permitted?) res = HTTPResponse.read_new(@socket)
end while HTTPContinue === res end while HTTPContinue === res
yield res if block_given? res.reading_body(@socket, req.response_body_permitted?) {
yield res if block_given?
}
end_transport req, res end_transport req, res
res res
@ -726,24 +791,26 @@ module Net
if @socket.closed? then if @socket.closed? then
reconn_socket reconn_socket
end end
if not req.body_exist? or @seems_1_0_server then if @seems_1_0_server then
req['connection'] = 'close'
end
if not req.response_body_permitted? and @close_on_empty_response then
req['connection'] = 'close' req['connection'] = 'close'
end end
req['host'] = addr_port() req['host'] = addr_port()
end end
def end_transport( req, res ) def end_transport( req, res )
res.__send__ :terminate
@curr_http_version = res.http_version @curr_http_version = res.http_version
if not res.body then if not res.body and @close_on_empty_response then
D 'Conn close'
@socket.close @socket.close
elsif keep_alive? req, res then elsif keep_alive? req, res then
D 'Conn keep-alive' D 'Conn keep-alive'
if @socket.closed? then # (only) read stream had been closed if @socket.closed? then
D 'Conn (but seems 1.0 server)' D 'Conn (but seems 1.0 server)'
@seems_1_0_server = true @seems_1_0_server = true
@socket.close
end end
else else
D 'Conn close' D 'Conn close'
@ -776,9 +843,9 @@ module Net
end end
def D( msg ) def D( msg )
if @dout then if @debug_output then
@dout << msg @debug_output << msg
@dout << "\n" @debug_output << "\n"
end end
end end
@ -891,11 +958,9 @@ module Net
alias set_range range= alias set_range range=
def content_length def content_length
s = @header['content-length'] s = @header['content-length'] or return nil
s or return nil m = /\d+/.match(s) or
raise HTTPHeaderSyntaxError, 'wrong Content-Length format'
m = /\d+/.match(s)
m or raise HTTPHeaderSyntaxError, 'wrong Content-Length format'
m[0].to_i m[0].to_i
end end
@ -905,17 +970,14 @@ module Net
end end
def content_range def content_range
s = @header['content-range'] s = @header['content-range'] or return nil
s or return nil m = %r<bytes\s+(\d+)-(\d+)/(?:\d+|\*)>i.match(s) or
raise HTTPHeaderSyntaxError, 'wrong Content-Range format'
m = %r<bytes\s+(\d+)-(\d+)/(?:\d+|\*)>i.match( s )
m or raise HTTPHeaderSyntaxError, 'wrong Content-Range format'
m[1].to_i .. m[2].to_i + 1 m[1].to_i .. m[2].to_i + 1
end end
def range_length def range_length
r = content_range r = self.content_range
r and r.length r and r.length
end end
@ -956,7 +1018,7 @@ module Net
attr_reader :path attr_reader :path
def inspect def inspect
"\#<#{self.type} #{@method}>" "\#<#{self.class} #{@method}>"
end end
def request_body_permitted? def request_body_permitted?
@ -973,8 +1035,7 @@ module Net
# write # write
# #
private # internal use only
def exec( sock, ver, path, body ) def exec( sock, ver, path, body )
if body then if body then
check_body_premitted check_body_premitted
@ -984,6 +1045,8 @@ module Net
end end
end end
private
def check_body_premitted def check_body_premitted
request_body_permitted? or request_body_permitted? or
raise ArgumentError, 'HTTP request body is not premitted' raise ArgumentError, 'HTTP request body is not premitted'
@ -1023,9 +1086,9 @@ module Net
class HTTPRequest < HTTPGenericRequest class HTTPRequest < HTTPGenericRequest
def initialize( path, initheader = nil ) def initialize( path, initheader = nil )
super type::METHOD, super self.class::METHOD,
type::REQUEST_HAS_BODY, self.class::REQUEST_HAS_BODY,
type::RESPONSE_HAS_BODY, self.class::RESPONSE_HAS_BODY,
path, initheader path, initheader
end end
@ -1083,132 +1146,152 @@ module Net
HAS_BODY = true HAS_BODY = true
EXCEPTION_TYPE = ProtocolError EXCEPTION_TYPE = ProtocolError
end end
class HTTPInformation < HTTPResponse class HTTPInformation < HTTPResponse # 1xx
HAS_BODY = false HAS_BODY = false
EXCEPTION_TYPE = ProtocolError EXCEPTION_TYPE = ProtocolError
end end
class HTTPSuccess < HTTPResponse class HTTPSuccess < HTTPResponse # 2xx
HAS_BODY = true HAS_BODY = true
EXCEPTION_TYPE = ProtocolError EXCEPTION_TYPE = ProtocolError
end end
class HTTPRedirection < HTTPResponse class HTTPRedirection < HTTPResponse # 3xx
HAS_BODY = true HAS_BODY = true
EXCEPTION_TYPE = ProtoRetriableError EXCEPTION_TYPE = ProtoRetriableError
end end
class HTTPClientError < HTTPResponse class HTTPClientError < HTTPResponse # 4xx
HAS_BODY = true HAS_BODY = true
EXCEPTION_TYPE = ProtoFatalError EXCEPTION_TYPE = ProtoFatalError
end end
class HTTPServerError < HTTPResponse class HTTPServerError < HTTPResponse # 5xx
HAS_BODY = true HAS_BODY = true
EXCEPTION_TYPE = ProtoServerError EXCEPTION_TYPE = ProtoServerError
end end
class HTTPContinue < HTTPInformation
class HTTPContinue < HTTPInformation # 100
HAS_BODY = false HAS_BODY = false
end end
class HTTPSwitchProtocol < HTTPInformation class HTTPSwitchProtocol < HTTPInformation # 101
HAS_BODY = false HAS_BODY = false
end end
class HTTPOK < HTTPSuccess
class HTTPOK < HTTPSuccess # 200
HAS_BODY = true HAS_BODY = true
end end
class HTTPCreated < HTTPSuccess class HTTPCreated < HTTPSuccess # 201
HAS_BODY = true HAS_BODY = true
end end
class HTTPAccepted < HTTPSuccess class HTTPAccepted < HTTPSuccess # 202
HAS_BODY = true HAS_BODY = true
end end
class HTTPNonAuthoritativeInformation < HTTPSuccess class HTTPNonAuthoritativeInformation < HTTPSuccess # 203
HAS_BODY = true HAS_BODY = true
end end
class HTTPNoContent < HTTPSuccess class HTTPNoContent < HTTPSuccess # 204
HAS_BODY = false HAS_BODY = false
end end
class HTTPResetContent < HTTPSuccess class HTTPResetContent < HTTPSuccess # 205
HAS_BODY = false HAS_BODY = false
end end
class HTTPPartialContent < HTTPSuccess class HTTPPartialContent < HTTPSuccess # 206
HAS_BODY = true HAS_BODY = true
end end
class HTTPMultipleChoice < HTTPRedirection
class HTTPMultipleChoice < HTTPRedirection # 300
HAS_BODY = true HAS_BODY = true
end end
class HTTPMovedPermanently < HTTPRedirection class HTTPMovedPermanently < HTTPRedirection # 301
HAS_BODY = true HAS_BODY = true
end end
class HTTPMovedTemporarily < HTTPRedirection class HTTPFound < HTTPRedirection # 302
HAS_BODY = true HAS_BODY = true
end end
class HTTPNotModified < HTTPRedirection HTTPMovedTemporarily = HTTPFound
class HTTPSeeOther < HTTPRedirection # 303
HAS_BODY = true
end
class HTTPNotModified < HTTPRedirection # 304
HAS_BODY = false HAS_BODY = false
end end
class HTTPUseProxy < HTTPRedirection class HTTPUseProxy < HTTPRedirection # 305
HAS_BODY = false HAS_BODY = false
end end
class HTTPBadRequest < HTTPClientError # 306 unused
class HTTPTemporaryRedirect < HTTPRedirection # 307
HAS_BODY = true HAS_BODY = true
end end
class HTTPUnauthorized < HTTPClientError
class HTTPBadRequest < HTTPClientError # 400
HAS_BODY = true HAS_BODY = true
end end
class HTTPPaymentRequired < HTTPClientError class HTTPUnauthorized < HTTPClientError # 401
HAS_BODY = true HAS_BODY = true
end end
class HTTPForbidden < HTTPClientError class HTTPPaymentRequired < HTTPClientError # 402
HAS_BODY = true HAS_BODY = true
end end
class HTTPNotFound < HTTPClientError class HTTPForbidden < HTTPClientError # 403
HAS_BODY = true HAS_BODY = true
end end
class HTTPMethodNotAllowed < HTTPClientError class HTTPNotFound < HTTPClientError # 404
HAS_BODY = true HAS_BODY = true
end end
class HTTPNotAcceptable < HTTPClientError class HTTPMethodNotAllowed < HTTPClientError # 405
HAS_BODY = true HAS_BODY = true
end end
class HTTPProxyAuthenticationRequired < HTTPClientError class HTTPNotAcceptable < HTTPClientError # 406
HAS_BODY = true HAS_BODY = true
end end
class HTTPRequestTimeOut < HTTPClientError class HTTPProxyAuthenticationRequired < HTTPClientError # 407
HAS_BODY = true HAS_BODY = true
end end
class HTTPConflict < HTTPClientError class HTTPRequestTimeOut < HTTPClientError # 408
HAS_BODY = true HAS_BODY = true
end end
class HTTPGone < HTTPClientError class HTTPConflict < HTTPClientError # 409
HAS_BODY = true HAS_BODY = true
end end
class HTTPLengthRequired < HTTPClientError class HTTPGone < HTTPClientError # 410
HAS_BODY = true HAS_BODY = true
end end
class HTTPPreconditionFailed < HTTPClientError class HTTPLengthRequired < HTTPClientError # 411
HAS_BODY = true HAS_BODY = true
end end
class HTTPRequestEntityTooLarge < HTTPClientError class HTTPPreconditionFailed < HTTPClientError # 412
HAS_BODY = true HAS_BODY = true
end end
class HTTPRequestURITooLarge < HTTPClientError class HTTPRequestEntityTooLarge < HTTPClientError # 413
HAS_BODY = true HAS_BODY = true
end end
class HTTPUnsupportedMediaType < HTTPClientError class HTTPRequestURITooLong < HTTPClientError # 414
HAS_BODY = true HAS_BODY = true
end end
class HTTPInternalServerError < HTTPServerError HTTPRequestURITooLarge = HTTPRequestURITooLong
class HTTPUnsupportedMediaType < HTTPClientError # 415
HAS_BODY = true HAS_BODY = true
end end
class HTTPNotImplemented < HTTPServerError class HTTPRequestedRangeNotSatisfiable < HTTPClientError # 416
HAS_BODY = true HAS_BODY = true
end end
class HTTPBadGateway < HTTPServerError class HTTPExpectationFailed < HTTPClientError # 417
HAS_BODY = true HAS_BODY = true
end end
class HTTPServiceUnavailable < HTTPServerError
class HTTPInternalServerError < HTTPServerError # 500
HAS_BODY = true HAS_BODY = true
end end
class HTTPGatewayTimeOut < HTTPServerError class HTTPNotImplemented < HTTPServerError # 501
HAS_BODY = true HAS_BODY = true
end end
class HTTPVersionNotSupported < HTTPServerError 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 HAS_BODY = true
end end
@ -1236,9 +1319,11 @@ module Net
'300' => HTTPMultipleChoice, '300' => HTTPMultipleChoice,
'301' => HTTPMovedPermanently, '301' => HTTPMovedPermanently,
'302' => HTTPMovedTemporarily, '302' => HTTPFound,
'303' => HTTPSeeOther,
'304' => HTTPNotModified, '304' => HTTPNotModified,
'305' => HTTPUseProxy, '305' => HTTPUseProxy,
'307' => HTTPTemporaryRedirect,
'400' => HTTPBadRequest, '400' => HTTPBadRequest,
'401' => HTTPUnauthorized, '401' => HTTPUnauthorized,
@ -1254,8 +1339,10 @@ module Net
'411' => HTTPLengthRequired, '411' => HTTPLengthRequired,
'412' => HTTPPreconditionFailed, '412' => HTTPPreconditionFailed,
'413' => HTTPRequestEntityTooLarge, '413' => HTTPRequestEntityTooLarge,
'414' => HTTPRequestURITooLarge, '414' => HTTPRequestURITooLong,
'415' => HTTPUnsupportedMediaType, '415' => HTTPUnsupportedMediaType,
'416' => HTTPRequestedRangeNotSatisfiable,
'417' => HTTPExpectationFailed,
'501' => HTTPInternalServerError, '501' => HTTPInternalServerError,
'501' => HTTPNotImplemented, '501' => HTTPNotImplemented,
@ -1268,9 +1355,9 @@ module Net
class << self class << self
def read_new( sock, hasbody ) def read_new( sock )
httpv, code, msg = read_status_line(sock) httpv, code, msg = read_status_line(sock)
res = response_class(code).new( httpv, code, msg, sock, hasbody ) res = response_class(code).new(httpv, code, msg)
each_response_header(sock) do |k,v| each_response_header(sock) do |k,v|
if res.key? k then if res.key? k then
res[k] << ', ' << v res[k] << ', ' << v
@ -1314,12 +1401,10 @@ module Net
include HTTPHeader include HTTPHeader
def initialize( httpv, code, msg, sock, hasbody ) def initialize( httpv, code, msg )
@http_version = httpv @http_version = httpv
@code = code @code = code
@message = msg @message = msg
@socket = sock
@body_exist = hasbody
@header = {} @header = {}
@body = nil @body = nil
@ -1332,7 +1417,7 @@ module Net
alias msg message alias msg message
def inspect def inspect
"#<#{type} #{@code} readbody=#{@read}>" "#<#{self.class} #{@code} readbody=#{@read}>"
end end
# #
@ -1340,15 +1425,15 @@ module Net
# #
def code_type def code_type
self.type self.class
end end
def error! def error!
raise error_type.new(@code + ' ' + @message.dump, self) raise error_type().new(@code + ' ' + @message.dump, self)
end end
def error_type def error_type
type::EXCEPTION_TYPE self.class::EXCEPTION_TYPE
end end
def value def value
@ -1356,7 +1441,7 @@ module Net
end end
# #
# header (for backward compatibility) # header (for backward compatibility only; DO NOT USE)
# #
def response def response
@ -1370,16 +1455,25 @@ module Net
# body # body
# #
# internal use only
def reading_body( sock, reqmethodallowbody )
@socket = sock
@body_exist = reqmethodallowbody && self.class.body_permitted?
yield
self.body
@socket = nil
end
def read_body( dest = nil, &block ) def read_body( dest = nil, &block )
if @read then if @read then
(dest or block) and (dest or block) and
raise IOError, "#{type}\#read_body called twice with argument" raise IOError, "#{self.class}\#read_body called twice"
return @body return @body
end end
to = procdest(dest, block) to = procdest(dest, block)
stream_check stream_check
if @body_exist and self.type.body_permitted? then if @body_exist then
read_body_0 to read_body_0 to
@body = to @body = to
else else
@ -1395,10 +1489,6 @@ module Net
private private
def terminate
read_body
end
def read_body_0( dest ) def read_body_0( dest )
if chunked? then if chunked? then
read_chunked dest read_chunked dest

View File

@ -76,17 +76,17 @@ module Net
def initialize( addr, port = nil ) def initialize( addr, port = nil )
@address = addr @address = addr
@port = port || type.default_port @port = port || self.class.default_port
@command = nil @command = nil
@socket = nil @socket = nil
@active = false @started = false
@open_timeout = 30 @open_timeout = 30
@read_timeout = 60 @read_timeout = 60
@dout = nil @debug_output = nil
end end
attr_reader :address attr_reader :address
@ -96,6 +96,7 @@ module Net
attr_reader :socket attr_reader :socket
attr_accessor :open_timeout attr_accessor :open_timeout
attr_reader :read_timeout attr_reader :read_timeout
def read_timeout=( sec ) def read_timeout=( sec )
@ -103,18 +104,18 @@ module Net
@read_timeout = sec @read_timeout = sec
end end
def active? def started?
@active @started
end end
alias active? started?
def set_debug_output( arg ) # un-documented def set_debug_output( arg ) # un-documented
@dout = arg @debug_output = arg
end end
alias set_pipe set_debug_output
def inspect def inspect
"#<#{type} #{address}:#{port} open=#{active?}>" "#<#{self.class} #{@address}:#{@port} open=#{active?}>"
end end
# #
@ -122,20 +123,20 @@ module Net
# #
def start( *args ) def start( *args )
@active and raise IOError, 'protocol has been opened already' @started and raise IOError, 'protocol has been opened already'
if block_given? then if block_given? then
begin begin
do_start( *args ) do_start( *args )
@active = true @started = true
return yield(self) return yield(self)
ensure ensure
finish if @active finish if @started
end end
end end
do_start( *args ) do_start( *args )
@active = true @started = true
self self
end end
@ -144,9 +145,9 @@ module Net
# abstract do_start() # abstract do_start()
def conn_socket def conn_socket
@socket = type.socket_type.open( @socket = self.class.socket_type.open(
conn_address(), conn_port(), conn_address(), conn_port(),
@open_timeout, @read_timeout, @dout ) @open_timeout, @read_timeout, @debug_output )
on_connect on_connect
end end
@ -159,7 +160,7 @@ module Net
end end
def conn_command def conn_command
@command = type.command_type.new(@socket) @command = self.class.command_type.new(@socket)
end end
def on_connect def on_connect
@ -172,9 +173,9 @@ module Net
public public
def finish def finish
active? or raise IOError, 'closing already closed protocol' @started or raise IOError, 'closing already closed protocol'
do_finish do_finish
@active = false @started = false
nil nil
end end
@ -208,15 +209,21 @@ module Net
super() super()
end end
attr_reader :code_type, :code, :message attr_reader :code_type
attr_reader :code
attr_reader :message
alias msg message alias msg message
def inspect def inspect
"#<#{type} #{code}>" "#<#{self.class} #{@code}>"
end end
def error! def error!
raise @code_type.error_type.new( code + ' ' + msg.dump, self ) raise error_type().new(code + ' ' + @message.dump, self)
end
def error_type
@code_type.error_type
end end
end end
@ -243,7 +250,7 @@ module Net
alias data response alias data response
def inspect def inspect
"#<#{type}>" "#<#{self.class} #{self.message}>"
end end
end end
@ -253,28 +260,26 @@ module Net
def initialize( paren, err ) def initialize( paren, err )
@parents = [self] + paren @parents = [self] + paren
@err = err @error_type = err
end end
def parents def parents
@parents.dup @parents.dup
end end
def inspect attr_reader :error_type
"#<#{type} #{sprintf '0x%x', __id__}>"
end
def error_type def inspect
@err "#<#{self.class} #{sprintf '0x%x', __id__}>"
end end
def ===( response ) def ===( response )
response.code_type.parents.each {|c| return true if c == self } response.code_type.parents.each {|c| c == self and return true }
false false
end end
def mkchild( err = nil ) def mkchild( err = nil )
type.new( @parents, err || @err ) self.class.new(@parents, err || @error_type)
end end
end end
@ -304,7 +309,7 @@ module Net
attr_reader :last_reply attr_reader :last_reply
def inspect def inspect
"#<#{type}>" "#<#{self.class} socket=#{@socket.inspect} critical=#{@atomic}>"
end end
# abstract quit() # abstract quit()
@ -331,7 +336,7 @@ module Net
end end
# #
# error handle # critical session
# #
public public
@ -366,7 +371,7 @@ module Net
@address = addr @address = addr
@port = port @port = port
@read_timeout = rtime @read_timeout = rtime
@debugout = dout @debug_output = dout
@socket = nil @socket = nil
@rbuf = nil @rbuf = nil
@ -502,7 +507,7 @@ module Net
def rbuf_moveto( dest, len ) def rbuf_moveto( dest, len )
dest << (s = @rbuf.slice!(0, len)) dest << (s = @rbuf.slice!(0, len))
@debugout << %Q[-> #{s.dump}\n] if @debugout @debug_output << %Q[-> #{s.dump}\n] if @debug_output
len len
end end
@ -559,15 +564,15 @@ module Net
def writing def writing
@writtensize = 0 @writtensize = 0
@debugout << '<- ' if @debugout @debug_output << '<- ' if @debug_output
yield yield
@socket.flush @socket.flush
@debugout << "\n" if @debugout @debug_output << "\n" if @debug_output
@writtensize @writtensize
end end
def do_write( str ) def do_write( str )
@debugout << str.dump if @debugout @debug_output << str.dump if @debug_output
@writtensize += (n = @socket.write(str)) @writtensize += (n = @socket.write(str))
n n
end end
@ -693,18 +698,18 @@ module Net
def D_off( msg ) def D_off( msg )
D msg D msg
@savedo, @debugout = @debugout, nil @savedo, @debug_output = @debug_output, nil
end end
def D_on( msg ) def D_on( msg )
@debugout = @savedo @debug_output = @savedo
D msg D msg
end end
def D( msg ) def D( msg )
@debugout or return @debug_output or return
@debugout << msg @debug_output << msg
@debugout << "\n" @debug_output << "\n"
end end
end end