summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authoraamine <aamine@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2000-03-27 15:52:27 +0000
committeraamine <aamine@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2000-03-27 15:52:27 +0000
commit9fd5174ef3aebe3d862289b4c646e65b2400b2f9 (patch)
tree36ba0828cb3b1f2bb70a53e7661a6e9ca7162f78 /lib
parent0dcf7498b10c7fd4739b34236502efd8e0f8353c (diff)
v1.1.11
o all: use "critical" to avoid duplicated command dispatch o http.rb: change get2, post2 usage (HTTPWriter) o http.rb: entity reading algorithm is better o http.rb: more reply code (4xx, 5xx) o protocol.rb: arguments of "connect" can be omitted o protocol.rb: "quit" is not template method (now do_quit is removed) o protocol.rb: ReplyCode.error_type was not work: using module_eval git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@657 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r--lib/net/http.rb347
-rw-r--r--lib/net/pop.rb86
-rw-r--r--lib/net/protocol.rb58
-rw-r--r--lib/net/smtp.rb32
4 files changed, 350 insertions, 173 deletions
diff --git a/lib/net/http.rb b/lib/net/http.rb
index 14f9da4003..009850abbc 100644
--- a/lib/net/http.rb
+++ b/lib/net/http.rb
@@ -58,19 +58,18 @@ class HTTPBadResponse < HTTPError; end
: post( path, data, header = nil, dest = '' )
: post( path, data, header = nil ) {|str| .... }
- post "data"(must be String now) to "path" (and get entity body).
+ post "data"(must be String now) to "path".
+ If body exists, also get entity body.
+ It is written to "dest" by using "<<" method.
"header" must be a Hash like { 'Accept' => '*/*', ... }.
- Data is written to "dest" by using "<<" method.
This method returns response header (Hash) and "dest".
- If called as iterator, give a part String of entity body.
-
- ATTENTION: entity body could be empty
+ If called as iterator, gives a part String of entity body.
-: get2( path, header = nil )
+: get2( path, header = nil ) {|writer| .... }
send GET request for "path".
"header" must be a Hash like { 'Accept' => '*/*', ... }.
- This method returns response header (Hash).
+ This method gives HTTPWriter object to block.
: get_body( dest = '' )
: get_body {|str| .... }
@@ -78,7 +77,31 @@ class HTTPBadResponse < HTTPError; end
Data is written in "dest" by using "<<" method.
This method returns "dest".
- If called as iterator, give a part String of entity body.
+ If called as iterator, gives a part String of entity body.
+
+: post2( path, data, header = nil ) {|writer| .... }
+ post "data"(must be String now) to "path".
+ "header" must be a Hash like { 'Accept' => '*/*', ... }.
+ This method gives HTTPWriter object to block.
+
+
+= class HTTPWriter
+
+== Methods
+
+: header
+ HTTP header.
+
+: response
+ ReplyCode object.
+
+: entity( dest = '' )
+: body( dest = '' )
+ entity body.
+
+: entity {|str| ... }
+ get entity body by using iterator.
+ If this method is called twice, block is not called.
=end
@@ -87,20 +110,24 @@ class HTTPBadResponse < HTTPError; end
protocol_param :port, '80'
protocol_param :command_type, '::Net::HTTPCommand'
-
- def get( path, u_header = nil, dest = nil, &block )
- u_header = procheader( u_header )
+ def HTTP.procdest( dest, block )
if block then
- dest = ReadAdapter.new( block )
- ret = nil
+ return ReadAdapter.new( block ), nil
else
- dest = ret = ''
+ dest ||= ''
+ return dest, dest
end
+ end
+
+
+ def get( path, u_header = nil, dest = nil, &block )
+ u_header = procheader( u_header )
+ dest, ret = HTTP.procdest( dest, block )
resp = nil
connecting( u_header ) {
@command.get edit_path(path), u_header
resp = @command.get_response
- @command.try_get_body( resp, dest )
+ @command.get_body( resp, dest )
}
return resp['http-header'], ret
@@ -108,67 +135,82 @@ class HTTPBadResponse < HTTPError; end
def get2( path, u_header = nil )
u_header = procheader( u_header )
- only_header( :get, path, u_header )
+ connecting( u_header ) {
+ @command.get edit_path(path), u_header
+ tmp = HTTPWriter.new( @command )
+ yield tmp
+ tmp.off
+ }
end
+=begin c
def get_body( dest = '', &block )
if block then
dest = ReadAdapter.new( block )
end
- @command.try_get_body @response, dest
+ @command.get_body @response, dest
ensure_termination @u_header
dest
end
+=end
def head( path, u_header = nil )
u_header = procheader( u_header )
- header = only_header( :head, path, u_header )
- ensure_termination u_header
- header
+ resp = nil
+ connecting( u_header ) {
+ @command.head( edit_path(path), u_header )
+ resp = @command.get_response_no_body
+ }
+
+ resp['http-header']
end
def post( path, data, u_header = nil, dest = nil, &block )
u_header = procheader( u_header )
- if block then
- dest = ReadAdapter.new( block )
- ret = nil
- else
- dest = ret = ''
- end
+ dest, ret = HTTP.procdest( dest, block )
resp = nil
- connecting( u_header, true ) {
- @command.post path, u_header, data
+ connecting( u_header ) {
+ @command.post edit_path(path), u_header, data
resp = @command.get_response
- @command.try_get_body( resp, dest )
+ @command.get_body( resp, dest )
}
return resp['http-header'], ret
end
- def post2( path, data, u_header = {} )
+ def post2( path, data, u_header = nil )
u_header = procheader( u_header )
- only_header :post, path, u_header, data
+ connecting( u_header ) {
+ @command.post edit_path(path), u_header, data
+ tmp = HTTPWriter.new( @command )
+ yield tmp
+ tmp.off
+ }
end
# not tested because I could not setup apache (__;;;
- def put( path, src = nil, u_header = nil, &block )
+ def put( path, src, u_header = nil )
u_header = procheader( u_header )
- connecting( u_header, true ) {
+ ret = ''
+ connecting( u_header ) {
@command.put path, u_header, src, dest
+ resp = @comman.get_response
+ @command.get_body( resp, ret )
}
- header
+ return header, ret
end
private
+=begin c
def only_header( mid, path, u_header, data = nil )
@u_header = u_header
@response = nil
- ensure_connection u_header
+ connecting u_header
if data then
@command.send mid, edit_path(path), u_header, data
else
@@ -177,6 +219,7 @@ class HTTPBadResponse < HTTPError; end
@response = @command.get_response
@response['http-header']
end
+=end
# called when connecting
@@ -189,19 +232,19 @@ class HTTPBadResponse < HTTPError; end
end
end
- def connecting( u_header, putp = false )
- ensure_connection u_header
- yield
- ensure_termination u_header
- end
-
- def ensure_connection( u_header )
+ def connecting( u_header )
if not @socket then
u_header['Connection'] = 'Close'
start
elsif @socket.closed? then
@socket.reopen
end
+
+ if iterator? then
+ ret = yield
+ ensure_termination u_header
+ ret
+ end
end
def ensure_termination( u_header )
@@ -258,18 +301,82 @@ class HTTPBadResponse < HTTPError; end
HTTPSession = HTTP
- class HTTPSuccessCode < SuccessCode; end
- class HTTPCreatedCode < SuccessCode; end
- class HTTPAcceptedCode < SuccessCode; end
- class HTTPNoContentCode < SuccessCode; end
- class HTTPResetContentCode < SuccessCode; end
- class HTTPPartialContentCode < SuccessCode; end
+ class HTTPWriter
+
+ def initialize( command )
+ @command = command
+ @response = @header = @entity = nil
+ end
+
+ def response
+ unless @resp then
+ @resp = @command.get_response
+ end
+ @resp
+ end
+
+ def header
+ unless @header then
+ @header = response['http-header']
+ end
+ @header
+ end
+
+ def entity( dest = nil, &block )
+ dest, ret = HTTP.procdest( dest, block )
+ unless @entity then
+ @entity = @command.get_body( response, dest )
+ end
+ @entity
+ end
+ alias body entity
+
+ def off
+ entity
+ @command = nil
+ end
+
+ end
+
- class HTTPMultipleChoiceCode < RetryCode; end
- class HTTPMovedPermanentlyCode < RetryCode; end
- class HTTPMovedTemporarilyCode < RetryCode; end
- class HTTPNotModifiedCode < RetryCode; end
- class HTTPUseProxyCode < RetryCode; end
+ class HTTPSwitchProtocol < SuccessCode; end
+
+ class HTTPOK < SuccessCode; end
+ class HTTPCreated < SuccessCode; end
+ class HTTPAccepted < SuccessCode; end
+ class HTTPNonAuthoritativeInformation < SuccessCode; end
+ class HTTPNoContent < SuccessCode; end
+ class HTTPResetContent < SuccessCode; end
+ class HTTPPartialContent < SuccessCode; end
+
+ class HTTPMultipleChoice < RetryCode; end
+ class HTTPMovedPermanently < RetryCode; end
+ class HTTPMovedTemporarily < RetryCode; end
+ class HTTPNotModified < RetryCode; end
+ class HTTPUseProxy < RetryCode; end
+
+ class HTTPBadRequest < RetryCode; end
+ class HTTPUnauthorized < RetryCode; end
+ class HTTPPaymentRequired < RetryCode; end
+ class HTTPForbidden < FatalErrorCode; end
+ class HTTPNotFound < FatalErrorCode; end
+ class HTTPMethodNotAllowed < FatalErrorCode; end
+ class HTTPNotAcceptable < FatalErrorCode; end
+ class HTTPProxyAuthenticationRequired < RetryCode; end
+ class HTTPRequestTimeOut < FatalErrorCode; end
+ class HTTPConflict < FatalErrorCode; end
+ class HTTPGone < FatalErrorCode; end
+ class HTTPLengthRequired < FatalErrorCode; end
+ class HTTPPreconditionFailed < FatalErrorCode; end
+ class HTTPRequestEntityTooLarge < FatalErrorCode; end
+ class HTTPRequestURITooLarge < FatalErrorCode; end
+ class HTTPUnsupportedMediaType < FatalErrorCode; end
+
+ class HTTPNotImplemented < FatalErrorCode; end
+ class HTTPBadGateway < FatalErrorCode; end
+ class HTTPServiceUnavailable < FatalErrorCode; end
+ class HTTPGatewayTimeOut < FatalErrorCode; end
+ class HTTPVersionNotSupported < FatalErrorCode; end
class HTTPCommand < Command
@@ -292,30 +399,36 @@ class HTTPBadResponse < HTTPError; end
def get( path, u_header )
+ return unless begin_critical
request sprintf('GET %s HTTP/%s', path, HTTPVersion), u_header
end
def head( path, u_header )
+ return unless begin_critical
request sprintf('HEAD %s HTTP/%s', path, HTTPVersion), u_header
end
def post( path, u_header, data )
+ return unless begin_critical
request sprintf('POST %s HTTP/%s', path, HTTPVersion), u_header
@socket.write data
end
def put( path, u_header, src )
+ return unless begin_critical
request sprintf('PUT %s HTTP/%s', path, HTTPVersion), u_header
@socket.write_bin src
end
-
# def delete
# def trace
# def options
+ def quit
+ end
+
def get_response
rep = get_reply
@@ -327,35 +440,47 @@ class HTTPBadResponse < HTTPError; end
nm = /\A[^:]+/.match( line )[0].strip.downcase
header[nm] = line
end
-
rep['http-header'] = header
- reply_must rep, SuccessCode
rep
end
+ def check_response( resp )
+ reply_must resp, SuccessCode
+ end
+
def get_body( rep, dest )
header = rep['http-header']
- if chunked? header then
- read_chunked( dest, header )
- else
- if clen = content_length( header ) then
- @socket.read clen, dest
- else
- ##### "multipart/byteranges" check should be done here ...
- # now, length is designated by closing socket
- @socket.read_all dest
- @socket.close
+ if rep['body-exist'] then
+ if chunked? header then
+ read_chunked( dest, header )
+ else
+ if clen = content_length( header ) then
+ @socket.read clen, dest
+ else
+ if false then # "multipart/byteranges" check should be done
+ else
+ if header['Connection'] and
+ /connection:\s*close/i === header['Connection'] then
+ @socket.read_all dest
+ @socket.close
+ end
+ end
+ end
end
end
- end
+ end_critical
+ reply_must rep, SuccessCode
- def try_get_body( rep, dest )
- rep = get_reply while ContinueCode === rep
- return nil unless rep['body-exist']
+ dest
+ end
- get_body rep, dest
+ def get_response_no_body
+ resp = get_response
+ end_critical
+ reply_must resp, SuccessCode
+ resp
end
@@ -376,6 +501,50 @@ class HTTPBadResponse < HTTPError; end
end
+ CODE_TO_CLASS = {
+ '100' => [ContinueCode, false],
+ '100' => [HTTPSwitchProtocol, false],
+
+ '200' => [HTTPOK, true],
+ '201' => [HTTPCreated, true],
+ '202' => [HTTPAccepted, true],
+ '203' => [HTTPNonAuthoritativeInformation, true],
+ '204' => [HTTPNoContent, false],
+ '205' => [HTTPResetContent, false],
+ '206' => [HTTPPartialContent, true],
+
+ '300' => [HTTPMultipleChoice, true],
+ '301' => [HTTPMovedPermanently, true],
+ '302' => [HTTPMovedTemporarily, true],
+ '303' => [HTTPMovedPermanently, true],
+ '304' => [HTTPNotModified, false],
+ '305' => [HTTPUseProxy, false],
+
+ '400' => [HTTPBadRequest, true],
+ '401' => [HTTPUnauthorized, true],
+ '402' => [HTTPPaymentRequired, true],
+ '403' => [HTTPForbidden, true],
+ '404' => [HTTPNotFound, true],
+ '405' => [HTTPMethodNotAllowed, true],
+ '406' => [HTTPNotAcceptable, true],
+ '407' => [HTTPProxyAuthenticationRequired, true],
+ '408' => [HTTPRequestTimeOut, true],
+ '409' => [HTTPConflict, true],
+ '410' => [HTTPGone, true],
+ '411' => [FatalErrorCode, true],
+ '412' => [HTTPPreconditionFailed, true],
+ '413' => [HTTPRequestEntityTooLarge, true],
+ '414' => [HTTPRequestURITooLarge, true],
+ '415' => [HTTPUnsupportedMediaType, true],
+
+ '500' => [FatalErrorCode, true],
+ '501' => [HTTPNotImplemented, true],
+ '502' => [HTTPBadGateway, true],
+ '503' => [HTTPServiceUnavailable, true],
+ '504' => [HTTPGatewayTimeOut, true],
+ '505' => [HTTPVersionNotSupported, true]
+ }
+
def get_reply
str = @socket.readline
unless /\AHTTP\/(\d+\.\d+)?\s+(\d\d\d)\s*(.*)\z/i === str then
@@ -385,41 +554,9 @@ class HTTPBadResponse < HTTPError; end
status = $2
discrip = $3
- be = false
- klass = case status[0]
- when ?1 then
- case status[2]
- when ?0 then ContinueCode
- when ?1 then HTTPSuccessCode
- else UnknownCode
- end
- when ?2 then
- case status[2]
- when ?0 then be = true; HTTPSuccessCode
- when ?1 then be = false; HTTPSuccessCode
- when ?2 then be = true; HTTPSuccessCode
- when ?3 then be = true; HTTPSuccessCode
- when ?4 then be = false; HTTPNoContentCode
- when ?5 then be = false; HTTPResetContentCode
- when ?6 then be = true; HTTPPartialContentCode
- else UnknownCode
- end
- when ?3 then
- case status[2]
- when ?0 then be = true; HTTPMultipleChoiceCode
- when ?1 then be = true; HTTPMovedPermanentryCode
- when ?2 then be = true; HTTPMovedTemporarilyCode
- when ?3 then be = true; HTTPMovedPermanentryCode
- when ?4 then be = false; HTTPNotModifiedCode
- when ?5 then be = false; HTTPUseProxyCode
- else UnknownCode
- end
- when ?4 then ServerBusyCode
- when ?5 then FatalErrorCode
- else UnknownCode
- end
+ klass, bodyexist = CODE_TO_CLASS[status] || [UnknownCode, true]
code = klass.new( status, discrip )
- code['body-exist'] = be
+ code['body-exist'] = bodyexist
code
end
diff --git a/lib/net/pop.rb b/lib/net/pop.rb
index 616f537f52..7a41e44350 100644
--- a/lib/net/pop.rb
+++ b/lib/net/pop.rb
@@ -71,8 +71,9 @@ Net::Protocol
def do_start( acnt, pwd )
@command.auth( acnt, pwd )
- t = self.type.mail_type
+
@mails = []
+ t = type.mail_type
@command.list.each_with_index do |size,idx|
if size then
@mails.push t.new( idx, size, @command )
@@ -221,70 +222,81 @@ Net::POP3
def initialize( sock )
super
- check_reply SuccessCode
+ critical {
+ check_reply SuccessCode
+ }
end
def auth( acnt, pass )
- @socket.writeline 'USER ' + acnt
- check_reply_auth
-
- @socket.writeline( 'PASS ' + pass )
- ret = check_reply_auth
+ critical {
+ @socket.writeline 'USER ' + acnt
+ check_reply_auth
- return ret
+ @socket.writeline 'PASS ' + pass
+ check_reply_auth
+ }
end
def list
- getok 'LIST'
-
arr = []
- @socket.read_pendlist do |line|
- num, siz = line.split( / +/o )
- arr[ num.to_i ] = siz.to_i
- end
-
- return arr
+ critical {
+ getok 'LIST'
+ @socket.read_pendlist do |line|
+ num, siz = line.split( / +/o )
+ arr[ num.to_i ] = siz.to_i
+ end
+ }
+ arr
end
def rset
- getok 'RSET'
+ critical {
+ getok 'RSET'
+ }
end
def top( num, lines = 0, dest = '' )
- getok sprintf( 'TOP %d %d', num, lines )
- @socket.read_pendstr( dest )
+ critical {
+ getok sprintf( 'TOP %d %d', num, lines )
+ @socket.read_pendstr( dest )
+ }
end
def retr( num, dest = '', &block )
- getok sprintf( 'RETR %d', num )
- @socket.read_pendstr( dest, &block )
+ critical {
+ getok sprintf( 'RETR %d', num )
+ @socket.read_pendstr( dest, &block )
+ }
end
def dele( num )
- getok sprintf( 'DELE %d', num )
+ critical {
+ getok sprintf( 'DELE %d', num )
+ }
end
def uidl( num )
- rep = getok( sprintf 'UIDL %d', num )
- uid = rep.msg.split(' ')[1]
-
- uid
+ critical {
+ getok( sprintf 'UIDL %d', num ).msg.split(' ')[1]
+ }
end
- private
+ def quit
+ critical {
+ getok 'QUIT'
+ }
+ end
- def do_quit
- getok 'QUIT'
- end
+ private
def check_reply_auth
@@ -326,19 +338,17 @@ Net::POP3
def auth( acnt, pass )
- @socket.writeline( "APOP #{acnt} #{digest(@stamp + pass)}" )
- return check_reply_auth
+ critical {
+ @socket.writeline( "APOP #{acnt} #{digest(@stamp + pass)}" )
+ check_reply_auth
+ }
end
def digest( str )
- temp = MD5.new( str ).digest
-
ret = ''
- temp.each_byte do |i|
- ret << sprintf( '%02x', i )
- end
- return ret
+ MD5.new( str ).digest.each_byte {|i| ret << sprintf('%02x', i) }
+ ret
end
end
diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb
index 4f2bf17fd4..776dba7359 100644
--- a/lib/net/protocol.rb
+++ b/lib/net/protocol.rb
@@ -15,7 +15,7 @@ require 'socket'
module Net
- Version = '1.1.10'
+ Version = '1.1.11'
=begin
@@ -144,7 +144,7 @@ Object
def initialize( addr = nil, port = nil )
@address = addr || 'localhost'
- @port = port || self.type.port
+ @port = port || type.port
@active = false
@pipe = nil
@@ -160,11 +160,11 @@ Object
def start( *args )
return false if active?
- @active = true
begin
- connect @address, @port
+ connect
do_start *args
+ @active = true
yield if iterator?
ensure
finish if iterator?
@@ -174,7 +174,7 @@ Object
def finish
ret = active?
- do_finish if @command
+ do_finish
disconnect
@active = false
@@ -201,9 +201,9 @@ Object
end
- def connect( addr, port )
- @socket = self.type.socket_type.open( addr, port, @pipe )
- @command = self.type.command_type.new( @socket )
+ def connect( addr = @address, port = @port )
+ @socket = type.socket_type.open( addr, port, @pipe )
+ @command = type.command_type.new( @socket )
end
def disconnect
@@ -213,7 +213,7 @@ Object
end
@socket = nil
end
-
+
end
Session = Protocol
@@ -226,24 +226,17 @@ Object
@socket = sock
@error_occured = false
@last_reply = nil
+ @critical = false
end
attr_reader :socket, :error_occured, :last_reply
attr_writer :socket
- def quit
- if @socket and not @socket.closed? then
- do_quit
- @error_occured = false
- end
- end
+ # abstract quit
private
- def do_quit
- end
-
# abstract get_reply()
def check_reply( *oks )
@@ -266,7 +259,30 @@ Object
@socket.writeline line
check_reply ok
end
-
+
+
+ def critical
+ return if @critical
+ @critical = true
+ r = yield
+ @critical = false
+ r
+ end
+
+ def critical?
+ @critical
+ end
+
+ def begin_critical
+ ret = @critical
+ @critical = true
+ not ret
+ end
+
+ def end_critical
+ @critical = false
+ end
+
end
@@ -284,11 +300,11 @@ Object
class << self
def error_type( err )
- @err = err
+ module_eval "def self.get_error_type() #{err.name} end"
end
def error!( mes )
- raise @err, mes
+ raise get_error_type, mes
end
end
diff --git a/lib/net/smtp.rb b/lib/net/smtp.rb
index b2ac287c06..a1a2f5370f 100644
--- a/lib/net/smtp.rb
+++ b/lib/net/smtp.rb
@@ -121,33 +121,44 @@ Net::Protocol
def initialize( sock )
super
- check_reply SuccessCode
+ critical {
+ check_reply SuccessCode
+ }
end
def helo( fromdom )
- getok sprintf( 'HELO %s', fromdom )
+ critical {
+ getok sprintf( 'HELO %s', fromdom )
+ }
end
def ehlo( fromdom )
- getok sprintf( 'EHLO %s', fromdom )
+ critical {
+ getok sprintf( 'EHLO %s', fromdom )
+ }
end
def mailfrom( fromaddr )
- getok sprintf( 'MAIL FROM:<%s>', fromaddr )
+ critical {
+ getok sprintf( 'MAIL FROM:<%s>', fromaddr )
+ }
end
def rcpt( toaddrs )
toaddrs.each do |i|
- getok sprintf( 'RCPT TO:<%s>', i )
+ critical {
+ getok sprintf( 'RCPT TO:<%s>', i )
+ }
end
end
def data
+ return unless begin_critical
getok 'DATA', ContinueCode
end
@@ -155,16 +166,19 @@ Net::Protocol
def write_mail( mailsrc = nil, &block )
@socket.write_pendstr mailsrc, &block
check_reply SuccessCode
+ end_critical
end
alias sendmail write_mail
- private
+ def quit
+ critical {
+ getok 'QUIT'
+ }
+ end
- def do_quit
- getok 'QUIT'
- end
+ private
def get_reply