summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/net/http.rb368
-rw-r--r--lib/net/pop.rb4
-rw-r--r--lib/net/protocol.rb214
-rw-r--r--lib/net/smtp.rb12
4 files changed, 332 insertions, 266 deletions
diff --git a/lib/net/http.rb b/lib/net/http.rb
index 009850abbcc..4a61e0c7473 100644
--- a/lib/net/http.rb
+++ b/lib/net/http.rb
@@ -15,10 +15,7 @@ require 'net/protocol'
module Net
-
-class HTTPError < ProtocolError; end
-class HTTPBadResponse < HTTPError; end
-
+ class HTTPBadResponse < StandardError; end
=begin
@@ -43,18 +40,20 @@ class HTTPBadResponse < HTTPError; end
get data from "path" on connecting host.
"header" must be a Hash like { 'Accept' => '*/*', ... }.
Data is written to "dest" by using "<<" method.
- This method returns response header (Hash) and "dest".
+ This method returns Net::HTTPResponse object and "dest".
If called as iterator, give a part String of entity body.
: head( path, header = nil )
get only header from "path" on connecting host.
"header" is a Hash like { 'Accept' => '*/*', ... }.
- This method returns header as a Hash like
+ This method returns Net::HTTPResponse object.
+ You can http header from this object like:
- { 'content-length' => 'Content-Length: 2554',
- 'content-type' => 'Content-Type: text/html',
- ... }
+ response['content-length'] #-> '2554'
+ response['content-type'] #-> 'text/html'
+ response['Content-Type'] #-> 'text/html'
+ response['CoNtEnT-tYpe'] #-> 'text/html'
: post( path, data, header = nil, dest = '' )
: post( path, data, header = nil ) {|str| .... }
@@ -62,42 +61,58 @@ class HTTPBadResponse < HTTPError; end
If body exists, also get entity body.
It is written to "dest" by using "<<" method.
"header" must be a Hash like { 'Accept' => '*/*', ... }.
- This method returns response header (Hash) and "dest".
+ This method returns Net::HTTPResponse object and "dest".
If called as iterator, gives a part String of entity body.
: get2( path, header = nil ) {|writer| .... }
send GET request for "path".
"header" must be a Hash like { 'Accept' => '*/*', ... }.
- This method gives HTTPWriter object to block.
-
-: get_body( dest = '' )
-: get_body {|str| .... }
- gets entity body of forwarded 'get2' or 'post2' methods.
- Data is written in "dest" by using "<<" method.
- This method returns "dest".
-
- If called as iterator, gives a part String of entity body.
+ This method gives HTTPReadAdapter object to block.
: 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.
+ This method gives HTTPReadAdapter object to block.
-= class HTTPWriter
+= class HTTPResponse
== Methods
-: header
- HTTP header.
+HTTP response object.
+All "key" is case-insensitive.
+
+: code
+ HTTP result code. ex. '302'
+
+: message
+ HTTP result message. ex. 'Not Found'
+
+: self[ key ]
+ returns header field for "key".
+ for HTTP, value is a string like 'text/plain'(for Content-Type),
+ '2045'(for Content-Length), 'bytes 0-1024/10024'(for Content-Range).
+ Multiple header had be joined by HTTP1.1 scheme.
+
+: self[ key ] = val
+ set field value for "key".
+: key?( key )
+ true if key is exist
+
+
+= class HTTPReadAdapter
+
+== Methods
+
+: header
: response
- ReplyCode object.
+ Net::HTTPResponse object
: entity( dest = '' )
: body( dest = '' )
- entity body.
+ entity body
: entity {|str| ... }
get entity body by using iterator.
@@ -130,30 +145,19 @@ class HTTPBadResponse < HTTPError; end
@command.get_body( resp, dest )
}
- return resp['http-header'], ret
+ return resp, ret
end
def get2( path, u_header = nil )
u_header = procheader( u_header )
connecting( u_header ) {
@command.get edit_path(path), u_header
- tmp = HTTPWriter.new( @command )
+ tmp = HTTPReadAdapter.new( @command )
yield tmp
tmp.off
}
end
-=begin c
- def get_body( dest = '', &block )
- if block then
- dest = ReadAdapter.new( block )
- end
- @command.get_body @response, dest
- ensure_termination @u_header
-
- dest
- end
-=end
def head( path, u_header = nil )
u_header = procheader( u_header )
@@ -163,7 +167,7 @@ class HTTPBadResponse < HTTPError; end
resp = @command.get_response_no_body
}
- resp['http-header']
+ resp
end
def post( path, data, u_header = nil, dest = nil, &block )
@@ -176,14 +180,14 @@ class HTTPBadResponse < HTTPError; end
@command.get_body( resp, dest )
}
- return resp['http-header'], ret
+ return resp, ret
end
def post2( path, data, u_header = nil )
u_header = procheader( u_header )
connecting( u_header ) {
@command.post edit_path(path), u_header, data
- tmp = HTTPWriter.new( @command )
+ tmp = HTTPReadAdapter.new( @command )
yield tmp
tmp.off
}
@@ -193,35 +197,20 @@ class HTTPBadResponse < HTTPError; end
def put( path, src, u_header = nil )
u_header = procheader( u_header )
ret = ''
+ resp = nil
connecting( u_header ) {
@command.put path, u_header, src, dest
resp = @comman.get_response
@command.get_body( resp, ret )
}
- return header, ret
+ return resp, ret
end
private
-=begin c
- def only_header( mid, path, u_header, data = nil )
- @u_header = u_header
- @response = nil
- connecting u_header
- if data then
- @command.send mid, edit_path(path), u_header, data
- else
- @command.send mid, edit_path(path), u_header
- end
- @response = @command.get_response
- @response['http-header']
- end
-=end
-
-
# called when connecting
def do_finish
unless @socket.closed? then
@@ -255,8 +244,8 @@ class HTTPBadResponse < HTTPError; end
end
def keep_alive?( header )
- if str = header['Connection'] then
- if /\A\s*keep-alive/i === str then
+ if header.key? 'connection' then
+ if /\A\s*keep-alive/i === header['connection'] then
return true
end
else
@@ -301,82 +290,126 @@ class HTTPBadResponse < HTTPError; end
HTTPSession = HTTP
- class HTTPWriter
+ class HTTPReadAdapter
def initialize( command )
@command = command
- @response = @header = @entity = nil
- end
-
- def response
- unless @resp then
- @resp = @command.get_response
- end
- @resp
+ @header = @body = nil
end
def header
unless @header then
- @header = response['http-header']
+ @header = @command.get_response
end
@header
end
+ alias response header
- def entity( dest = nil, &block )
+ def body( dest = nil, &block )
dest, ret = HTTP.procdest( dest, block )
- unless @entity then
- @entity = @command.get_body( response, dest )
+ unless @body then
+ @body = @command.get_body( response, dest )
end
- @entity
+ @body
end
- alias body entity
+ alias entity body
def off
- entity
+ body
@command = nil
end
end
- class HTTPSwitchProtocol < SuccessCode; end
+ class HTTPResponse < Response
+
+ def initialize( code_type, code, msg )
+ super
+ @data = {}
+ @http_body_exist = true
+ end
+
+ attr_accessor :http_body_exist
+
+ def []( key )
+ @data[ key.downcase ]
+ end
+
+ def []=( key, val )
+ @data[ key.downcase ] = val
+ end
+
+ def each( &block )
+ @data.each( &block )
+ end
+
+ def each_key( &block )
+ @data.each_key( &block )
+ end
+
+ def each_value( &block )
+ @data.each_value( &block )
+ end
+
+ def delete( key )
+ @data.delete key.downcase
+ end
+
+ def key?( key )
+ @data.key? key.downcase
+ end
+
+ def to_hash
+ @data.dup
+ end
+
+ end
+
+
+ HTTPSuccessCode = SuccessCode.mkchild
+ HTTPRetriableCode = RetriableCode.mkchild
+ HTTPFatalErrorCode = FatalErrorCode.mkchild
+
+
+ HTTPSwitchProtocol = HTTPSuccessCode.mkchild
- 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
+ HTTPOK = HTTPSuccessCode.mkchild
+ HTTPCreated = HTTPSuccessCode.mkchild
+ HTTPAccepted = HTTPSuccessCode.mkchild
+ HTTPNonAuthoritativeInformation = HTTPSuccessCode.mkchild
+ HTTPNoContent = HTTPSuccessCode.mkchild
+ HTTPResetContent = HTTPSuccessCode.mkchild
+ HTTPPartialContent = HTTPSuccessCode.mkchild
- class HTTPMultipleChoice < RetryCode; end
- class HTTPMovedPermanently < RetryCode; end
- class HTTPMovedTemporarily < RetryCode; end
- class HTTPNotModified < RetryCode; end
- class HTTPUseProxy < RetryCode; end
+ HTTPMultipleChoice = HTTPRetriableCode.mkchild
+ HTTPMovedPermanently = HTTPRetriableCode.mkchild
+ HTTPMovedTemporarily = HTTPRetriableCode.mkchild
+ HTTPNotModified = HTTPRetriableCode.mkchild
+ HTTPUseProxy = HTTPRetriableCode.mkchild
- 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
+ HTTPBadRequest = HTTPRetriableCode.mkchild
+ HTTPUnauthorized = HTTPRetriableCode.mkchild
+ HTTPPaymentRequired = HTTPRetriableCode.mkchild
+ HTTPForbidden = HTTPFatalErrorCode.mkchild
+ HTTPNotFound = HTTPFatalErrorCode.mkchild
+ HTTPMethodNotAllowed = HTTPFatalErrorCode.mkchild
+ HTTPNotAcceptable = HTTPFatalErrorCode.mkchild
+ HTTPProxyAuthenticationRequired = HTTPRetriableCode.mkchild
+ HTTPRequestTimeOut = HTTPFatalErrorCode.mkchild
+ HTTPConflict = HTTPFatalErrorCode.mkchild
+ HTTPGone = HTTPFatalErrorCode.mkchild
+ HTTPLengthRequired = HTTPFatalErrorCode.mkchild
+ HTTPPreconditionFailed = HTTPFatalErrorCode.mkchild
+ HTTPRequestEntityTooLarge = HTTPFatalErrorCode.mkchild
+ HTTPRequestURITooLarge = HTTPFatalErrorCode.mkchild
+ HTTPUnsupportedMediaType = HTTPFatalErrorCode.mkchild
+
+ HTTPNotImplemented = HTTPFatalErrorCode.mkchild
+ HTTPBadGateway = HTTPFatalErrorCode.mkchild
+ HTTPServiceUnavailable = HTTPFatalErrorCode.mkchild
+ HTTPGatewayTimeOut = HTTPFatalErrorCode.mkchild
+ HTTPVersionNotSupported = HTTPFatalErrorCode.mkchild
class HTTPCommand < Command
@@ -431,38 +464,48 @@ class HTTPBadResponse < HTTPError; end
def get_response
- rep = get_reply
- rep = get_reply while ContinueCode === rep
- header = {}
+ resp = get_reply
+ resp = get_reply while ContinueCode === resp
+
while true do
line = @socket.readline
break if line.empty?
- nm = /\A[^:]+/.match( line )[0].strip.downcase
- header[nm] = line
+
+ m = /\A([^:]+):\s*(.*)/p.match( line )
+ unless m then
+ raise HTTPBadResponse, 'wrong header line format'
+ end
+ nm = m[1]
+ line = m[2]
+ if resp.key? nm then
+ resp[nm] << ', ' << line
+ else
+ resp[nm] = line
+ end
end
- rep['http-header'] = header
- rep
+ resp
end
def check_response( resp )
reply_must resp, SuccessCode
end
- def get_body( rep, dest )
- header = rep['http-header']
-
- if rep['body-exist'] then
- if chunked? header then
- read_chunked( dest, header )
+ def get_body( resp, dest )
+ if resp.http_body_exist then
+ if chunked? resp then
+ read_chunked( dest, resp )
else
- if clen = content_length( header ) then
+ clen = content_length( resp )
+ if clen then
@socket.read clen, dest
else
- if false then # "multipart/byteranges" check should be done
+ clen = range_length( resp )
+ if clen then
+ @socket.read clen, dest
else
- if header['Connection'] and
- /connection:\s*close/i === header['Connection'] then
+ tmp = resp['connection']
+ if tmp and /close/i === tmp then
@socket.read_all dest
@socket.close
end
@@ -471,7 +514,7 @@ class HTTPBadResponse < HTTPError; end
end
end
end_critical
- reply_must rep, SuccessCode
+ reply_must resp, SuccessCode
dest
end
@@ -501,7 +544,7 @@ class HTTPBadResponse < HTTPError; end
end
- CODE_TO_CLASS = {
+ HTTPCODE_TO_OBJ = {
'100' => [ContinueCode, false],
'100' => [HTTPSwitchProtocol, false],
@@ -547,17 +590,18 @@ class HTTPBadResponse < HTTPError; end
def get_reply
str = @socket.readline
- unless /\AHTTP\/(\d+\.\d+)?\s+(\d\d\d)\s*(.*)\z/i === str then
+ m = /\AHTTP\/(\d+\.\d+)?\s+(\d\d\d)\s*(.*)\z/i.match( str )
+ unless m then
raise HTTPBadResponse, "wrong status line format: #{str}"
end
- @http_version = $1
- status = $2
- discrip = $3
+ @http_version = m[1]
+ status = m[2]
+ discrip = m[3]
- klass, bodyexist = CODE_TO_CLASS[status] || [UnknownCode, true]
- code = klass.new( status, discrip )
- code['body-exist'] = bodyexist
- code
+ klass, bodyexist = HTTPCODE_TO_OBJ[status] || [UnknownCode, true]
+ resp = HTTPResponse.new( klass, status, discrip )
+ resp.http_body_exist = bodyexist
+ resp
end
def read_chunked( ret, header )
@@ -567,10 +611,11 @@ class HTTPBadResponse < HTTPError; end
while true do
line = @socket.readline
- unless /[0-9a-hA-H]+/ === line then
+ m = /[0-9a-hA-H]+/.match( line )
+ unless m then
raise HTTPBadResponse, "chunk size not given"
end
- len = $&.hex
+ len = m[0].hex
break if len == 0
@socket.read( len, ret ); total += len
@socket.read 2 # \r\n
@@ -581,28 +626,47 @@ class HTTPBadResponse < HTTPError; end
end
header.delete 'transfer-encoding'
- header[ 'content-length' ] = "Content-Length: #{total}"
+ header[ 'content-length' ] = total.to_s
end
def content_length( header )
- unless str = header[ 'content-length' ] then
- return nil
- end
- unless /\Acontent-length:\s*(\d+)/i === str then
- raise HTTPBadResponse, "content-length format error"
+ if header.key? 'content-length' then
+ m = /\d+/.match( header['content-length'] )
+ unless m then
+ raise HTTPBadResponse, 'wrong Content-Length format'
+ end
+ m[0].to_i
+ else
+ nil
end
- $1.to_i
end
def chunked?( header )
- if str = header[ 'transfer-encoding' ] then
- if /\Atransfer-encoding:\s*chunked/i === str then
- return true
- end
+ str = header[ 'transfer-encoding' ]
+ if str and /(\A|\s+)chunked(?:\s+|\z)/i === str then
+ true
+ else
+ false
end
+ end
- false
+ def range_length( header )
+ if header.key? 'content-range' then
+ m = %r<bytes\s+(\d+)-(\d+)/\d+>.match( header['content-range'] )
+ unless m then
+ raise HTTPBadResponse, 'wrong Content-Range format'
+ end
+ l = m[2].to_i
+ u = m[1].to_i
+ if l > u then
+ nil
+ else
+ u - l
+ end
+ else
+ nil
+ end
end
end
diff --git a/lib/net/pop.rb b/lib/net/pop.rb
index 7a41e443507..65cd498f550 100644
--- a/lib/net/pop.rb
+++ b/lib/net/pop.rb
@@ -314,9 +314,9 @@ Net::POP3
str = @socket.readline
if /\A\+/ === str then
- return SuccessCode.new( str[0,3], str[3, str.size - 3].strip )
+ return Response.new( SuccessCode, str[0,3], str[3, str.size - 3].strip )
else
- return ErrorCode.new( str[0,4], str[4, str.size - 4].strip )
+ return Response.new( ErrorCode, str[0,4], str[4, str.size - 4].strip )
end
end
diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb
index 776dba73591..aa994016f49 100644
--- a/lib/net/protocol.rb
+++ b/lib/net/protocol.rb
@@ -15,7 +15,7 @@ require 'socket'
module Net
- Version = '1.1.11'
+ Version = '1.1.12'
=begin
@@ -95,7 +95,7 @@ Object
@port = port
end
- def connect( addr, port )
+ def connect( addr = nil, port = nil )
super @proxyaddr, @proxyport
end
private :connect
@@ -286,55 +286,21 @@ Object
end
- class ProtocolError < StandardError ; end
- class ProtoSyntaxError < ProtocolError ; end
- class ProtoFatalError < ProtocolError ; end
- class ProtoUnknownError < ProtocolError ; end
- class ProtoServerError < ProtocolError ; end
- class ProtoAuthError < ProtocolError ; end
- class ProtoCommandError < ProtocolError ; end
- class ProtoRetryError < ProtocolError ; end
+ class Response
- class ReplyCode
-
- class << self
-
- def error_type( err )
- module_eval "def self.get_error_type() #{err.name} end"
- end
-
- def error!( mes )
- raise get_error_type, mes
- end
-
- end
-
- def initialize( cod, mes )
- @code = cod
- @msg = mes
- @data = nil
- end
-
- attr_reader :code, :msg
-
- def []( key )
- if @data then
- @data[key]
- else
- nil
- end
- end
-
- def []=( key, val )
- unless h = @data then
- @data = h = {}
- end
- h[key] = val
+ def initialize( ctype, cno, msg )
+ @code_type = ctype
+ @code = cno
+ @message = msg
+ super()
end
+ attr_reader :code_type, :code, :message
+ alias msg message
def error!( sending )
- mes = <<MES
+ raise @code_type.error_type,
+ sprintf( <<MSG, @code, Net.quote(sending), Net.quote(@message) )
status %s
writing string is:
@@ -342,43 +308,58 @@ writing string is:
error message from server is:
%s
-MES
- type.error! sprintf( mes, @code, Net.quote(sending), Net.quote(@msg) )
+MSG
end
end
- class SuccessCode < ReplyCode
- error_type ProtoUnknownError
- end
- class ContinueCode < SuccessCode
- error_type ProtoUnknownError
- end
+ class ProtocolError < StandardError; end
+ class ProtoSyntaxError < ProtocolError; end
+ class ProtoFatalError < ProtocolError; end
+ class ProtoUnknownError < ProtocolError; end
+ class ProtoServerError < ProtocolError; end
+ class ProtoAuthError < ProtocolError; end
+ class ProtoCommandError < ProtocolError; end
+ class ProtoRetriableError < ProtocolError; end
+ ProtocRetryError = ProtoRetriableError
- class ErrorCode < ReplyCode
- error_type ProtocolError
- end
- class SyntaxErrorCode < ErrorCode
- error_type ProtoSyntaxError
- end
+ class Code
- class FatalErrorCode < ErrorCode
- error_type ProtoFatalError
- end
+ def initialize( paren, err )
+ @parents = paren
+ @err = err
- class ServerBusyCode < ErrorCode
- error_type ProtoServerError
- end
+ @parents.push self
+ end
- class RetryCode < ReplyCode
- error_type ProtoRetryError
- end
+ attr_reader :parents
+
+ def error_type
+ @err
+ end
+
+ def ===( response )
+ response.code_type.parents.reverse_each {|i| return true if i == self }
+ false
+ end
- class UnknownCode < ReplyCode
- error_type ProtoUnknownError
+ def mkchild( err = nil )
+ type.new( @parents + [self], err || @err )
+ end
+
end
+
+ ReplyCode = Code.new( [], ProtoUnknownError )
+ SuccessCode = ReplyCode.mkchild( ProtoUnknownError )
+ ContinueCode = ReplyCode.mkchild( ProtoUnknownError )
+ ErrorCode = ReplyCode.mkchild( ProtocolError )
+ SyntaxErrorCode = ErrorCode.mkchild( ProtoSyntaxError )
+ FatalErrorCode = ErrorCode.mkchild( ProtoFatalError )
+ ServerErrorCode = ErrorCode.mkchild( ProtoServerError )
+ RetriableCode = ReplyCode.mkchild( ProtoRetriableError )
+ UnknownCode = ReplyCode.mkchild( ProtoUnknownError )
@@ -415,6 +396,7 @@ MES
@addr = addr
@port = port
@pipe = pipe
+ @prepipe = nil
@closed = true
@ipaddr = ''
@@ -471,47 +453,49 @@ MES
TERMEXP = /\n|\r\n|\r/o
- def read( len, ret = '' )
- @pipe << "reading #{len} bytes...\n" if pre = @pipe ; @pipe = nil
+ def read( len, dest = '' )
+ @pipe << "reading #{len} bytes...\n" if @pipe; pipeoff
rsize = 0
while rsize + @buffer.size < len do
- rsize += writeinto( ret, @buffer.size )
+ rsize += writeinto( dest, @buffer.size )
fill_rbuf
end
- writeinto( ret, len - rsize )
+ writeinto( dest, len - rsize )
- @pipe << "read #{len} bytes\n" if @pipe = pre
- ret
+ @pipe << "read #{len} bytes\n" if pipeon
+ dest
end
- def read_all( ret = '' )
- @pipe << "reading all...\n" if pre = @pipe; @pipe = nil
+ def read_all( dest = '' )
+ @pipe << "reading all...\n" if @pipe; pipeoff
rsize = 0
begin
while true do
- rsize += writeinto( ret, @buffer.size )
+ rsize += writeinto( dest, @buffer.size )
fill_rbuf
end
rescue EOFError
;
end
- @pipe << "read #{rsize} bytes\n" if @pipe = pre
- ret
+ @pipe << "read #{rsize} bytes\n" if pipeon
+ dest
end
def readuntil( target )
- until idx = @buffer.index( target ) do
+ while true do
+ idx = @buffer.index( target )
+ break if idx
fill_rbuf
end
- ret = ''
- writeinto( ret, idx + target.size )
- ret
+ dest = ''
+ writeinto( dest, idx + target.size )
+ dest
end
@@ -522,8 +506,8 @@ MES
end
- def read_pendstr( dest = '' )
- @pipe << "reading text...\n" if pre = @pipe ; @pipe = nil
+ def read_pendstr( dest )
+ @pipe << "reading text...\n" if @pipe; pipeoff
rsize = 0
@@ -533,17 +517,16 @@ MES
dest << str
end
- @pipe << "read #{rsize} bytes\n" if @pipe = pre
+ @pipe << "read #{rsize} bytes\n" if pipeon
dest
end
def read_pendlist
- @pipe << "reading list...\n" if pre = @pipe ; @pipe = nil
+ @pipe << "reading list...\n" if @pipe; pipeoff
arr = []
str = nil
- call = iterator?
while (str = readuntil( CRLF )) != D_CRLF do
str.chop!
@@ -551,7 +534,7 @@ MES
yield str if iterator?
end
- @pipe << "read #{arr.size} lines\n" if @pipe = pre
+ @pipe << "read #{arr.size} lines\n" if pipeon
arr
end
@@ -565,12 +548,12 @@ MES
@buffer << @socket.sysread( READ_BLOCK )
end
- def writeinto( ret, len )
+ def writeinto( dest, len )
bsi = @buffer.size
- ret << @buffer[ 0, len ]
+ dest << @buffer[ 0, len ]
@buffer = @buffer[ len, bsi - len ]
- @pipe << %{read "#{Net.quote ret}"\n} if @pipe
+ @pipe << %{read "#{Net.quote dest}"\n} if @pipe
len
end
@@ -593,7 +576,7 @@ MES
end
- def write_bin( src, block = nil )
+ def write_bin( src, block )
do_write_beg
if block then
block.call WriteAdapter.new( self, :do_write_do )
@@ -606,12 +589,12 @@ MES
end
- def write_pendstr( src )
- @pipe << "writing text from #{src.type}\n" if pre = @pipe ; @pipe = nil
+ def write_pendstr( src, block )
+ @pipe << "writing text from #{src.type}\n" if @pipe; pipeoff
do_write_beg
- if iterator? then
- yield WriteAdapter.new( self, :write_pendstr_inner )
+ if block then
+ block.call WriteAdapter.new( self, :write_pendstr_inner )
else
write_pendstr_inner src
end
@@ -619,7 +602,7 @@ MES
do_write_do D_CRLF
wsize = do_write_fin
- @pipe << "wrote #{wsize} bytes text" if @pipe = pre
+ @pipe << "wrote #{wsize} bytes text" if pipeon
wsize
end
@@ -649,11 +632,13 @@ MES
adding( src ) do
beg = 0
buf = @wbuf
- while pos = buf.index( TERMEXP, beg ) do
+ while true do
+ pos = buf.index( TERMEXP, beg )
+ break unless pos
s = $&.size
break if pos + s == buf.size - 1 and buf[-1] == ?\r
- send mid, buf[ beg, pos - beg ] << CRLF
+ __send__ mid, buf[ beg, pos - beg ] << CRLF
beg = pos + s
end
@wbuf = buf[ beg, buf.size - beg ] if beg != 0
@@ -671,7 +656,9 @@ MES
end
when File
- while i = src.read( 512 ) do
+ while true do
+ i = src.read( 512 )
+ break unless i
@wbuf << i
yield
end
@@ -691,8 +678,10 @@ MES
buf << "\n" unless /\n|\r/o === buf[-1,1]
beg = 0
- while pos = buf.index( TERMEXP, beg ) do
- send mid, buf[ beg, pos - beg ] << CRLF
+ while true do
+ pos = buf.index( TERMEXP, beg )
+ break unless pos
+ __send__ mid, buf[ beg, pos - beg ] << CRLF
beg = pos + $&.size
end
end
@@ -727,6 +716,19 @@ MES
@writtensize
end
+
+ def pipeoff
+ @prepipe = @pipe
+ @pipe = nil
+ @prepipe
+ end
+
+ def pipeon
+ @pipe = @prepipe
+ @prepipe = nil
+ @pipe
+ end
+
end
diff --git a/lib/net/smtp.rb b/lib/net/smtp.rb
index a1a2f5370fb..e6b483252e5 100644
--- a/lib/net/smtp.rb
+++ b/lib/net/smtp.rb
@@ -76,12 +76,12 @@ Net::Protocol
def sendmail( mailsrc, fromaddr, toaddrs )
do_ready fromaddr, toaddrs
- @command.write_mail mailsrc
+ @command.write_mail mailsrc, nil
end
def ready( fromaddr, toaddrs, &block )
do_ready fromaddr, toaddrs
- @command.write_mail( &block )
+ @command.write_mail nil, block
end
@@ -163,8 +163,8 @@ Net::Protocol
end
- def write_mail( mailsrc = nil, &block )
- @socket.write_pendstr mailsrc, &block
+ def write_mail( mailsrc, block )
+ @socket.write_pendstr mailsrc, block
check_reply SuccessCode
end_critical
end
@@ -189,7 +189,7 @@ Net::Protocol
klass = case stat[0]
when ?2 then SuccessCode
when ?3 then ContinueCode
- when ?4 then ServerBusyCode
+ when ?4 then ServerErrorCode
when ?5 then
case stat[1]
when ?0 then SyntaxErrorCode
@@ -197,7 +197,7 @@ Net::Protocol
end
end
- klass.new( stat, arr.join('') )
+ Response.new( klass, stat, arr.join('') )
end