protocol.rb smtp.rb pop.rb http.rb version 1.1.12

o protocol.rb:  update Net::Protocol::Proxy#connect
o protocol.rb:  ReplyCode is not a class
o http.rb:  header value does not include header name
o http.rb:  header is not a Hash, but HTTPResponse


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@659 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
aamine 2000-03-31 13:02:40 +00:00
Родитель 9fd5174ef3
Коммит be72d9a5da
4 изменённых файлов: 332 добавлений и 266 удалений

Просмотреть файл

@ -15,10 +15,7 @@ require 'net/protocol'
module Net module Net
class HTTPBadResponse < StandardError; end
class HTTPError < ProtocolError; end
class HTTPBadResponse < HTTPError; end
=begin =begin
@ -43,18 +40,20 @@ class HTTPBadResponse < HTTPError; end
get data from "path" on connecting host. get data from "path" on connecting host.
"header" must be a Hash like { 'Accept' => '*/*', ... }. "header" must be a Hash like { 'Accept' => '*/*', ... }.
Data is written to "dest" by using "<<" method. 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. If called as iterator, give a part String of entity body.
: head( path, header = nil ) : head( path, header = nil )
get only header from "path" on connecting host. get only header from "path" on connecting host.
"header" is a Hash like { 'Accept' => '*/*', ... }. "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', response['content-length'] #-> '2554'
'content-type' => 'Content-Type: text/html', 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, dest = '' )
: post( path, data, header = nil ) {|str| .... } : post( path, data, header = nil ) {|str| .... }
@ -62,42 +61,58 @@ class HTTPBadResponse < HTTPError; end
If body exists, also get entity body. If body exists, also get entity body.
It is written to "dest" by using "<<" method. It is written to "dest" by using "<<" method.
"header" must be a Hash like { 'Accept' => '*/*', ... }. "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. If called as iterator, gives a part String of entity body.
: get2( path, header = nil ) {|writer| .... } : get2( path, header = nil ) {|writer| .... }
send GET request for "path". send GET request for "path".
"header" must be a Hash like { 'Accept' => '*/*', ... }. "header" must be a Hash like { 'Accept' => '*/*', ... }.
This method gives HTTPWriter object to block. This method gives HTTPReadAdapter 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.
: post2( path, data, header = nil ) {|writer| .... } : post2( path, data, header = nil ) {|writer| .... }
post "data"(must be String now) to "path". post "data"(must be String now) to "path".
"header" must be a Hash like { 'Accept' => '*/*', ... }. "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
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 == Methods
: header : header
HTTP header.
: response : response
ReplyCode object. Net::HTTPResponse object
: entity( dest = '' ) : entity( dest = '' )
: body( dest = '' ) : body( dest = '' )
entity body. entity body
: entity {|str| ... } : entity {|str| ... }
get entity body by using iterator. get entity body by using iterator.
@ -130,30 +145,19 @@ class HTTPBadResponse < HTTPError; end
@command.get_body( resp, dest ) @command.get_body( resp, dest )
} }
return resp['http-header'], ret return resp, ret
end end
def get2( path, u_header = nil ) def get2( path, u_header = nil )
u_header = procheader( u_header ) u_header = procheader( u_header )
connecting( u_header ) { connecting( u_header ) {
@command.get edit_path(path), u_header @command.get edit_path(path), u_header
tmp = HTTPWriter.new( @command ) tmp = HTTPReadAdapter.new( @command )
yield tmp yield tmp
tmp.off tmp.off
} }
end 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 ) def head( path, u_header = nil )
u_header = procheader( u_header ) u_header = procheader( u_header )
@ -163,7 +167,7 @@ class HTTPBadResponse < HTTPError; end
resp = @command.get_response_no_body resp = @command.get_response_no_body
} }
resp['http-header'] resp
end end
def post( path, data, u_header = nil, dest = nil, &block ) def post( path, data, u_header = nil, dest = nil, &block )
@ -176,14 +180,14 @@ class HTTPBadResponse < HTTPError; end
@command.get_body( resp, dest ) @command.get_body( resp, dest )
} }
return resp['http-header'], ret return resp, ret
end end
def post2( path, data, u_header = nil ) def post2( path, data, u_header = nil )
u_header = procheader( u_header ) u_header = procheader( u_header )
connecting( u_header ) { connecting( u_header ) {
@command.post edit_path(path), u_header, data @command.post edit_path(path), u_header, data
tmp = HTTPWriter.new( @command ) tmp = HTTPReadAdapter.new( @command )
yield tmp yield tmp
tmp.off tmp.off
} }
@ -193,35 +197,20 @@ class HTTPBadResponse < HTTPError; end
def put( path, src, u_header = nil ) def put( path, src, u_header = nil )
u_header = procheader( u_header ) u_header = procheader( u_header )
ret = '' ret = ''
resp = nil
connecting( u_header ) { connecting( u_header ) {
@command.put path, u_header, src, dest @command.put path, u_header, src, dest
resp = @comman.get_response resp = @comman.get_response
@command.get_body( resp, ret ) @command.get_body( resp, ret )
} }
return header, ret return resp, ret
end end
private 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 # called when connecting
def do_finish def do_finish
unless @socket.closed? then unless @socket.closed? then
@ -255,8 +244,8 @@ class HTTPBadResponse < HTTPError; end
end end
def keep_alive?( header ) def keep_alive?( header )
if str = header['Connection'] then if header.key? 'connection' then
if /\A\s*keep-alive/i === str then if /\A\s*keep-alive/i === header['connection'] then
return true return true
end end
else else
@ -301,82 +290,126 @@ class HTTPBadResponse < HTTPError; end
HTTPSession = HTTP HTTPSession = HTTP
class HTTPWriter class HTTPReadAdapter
def initialize( command ) def initialize( command )
@command = command @command = command
@response = @header = @entity = nil @header = @body = nil
end
def response
unless @resp then
@resp = @command.get_response
end
@resp
end end
def header def header
unless @header then unless @header then
@header = response['http-header'] @header = @command.get_response
end end
@header @header
end end
alias response header
def entity( dest = nil, &block ) def body( dest = nil, &block )
dest, ret = HTTP.procdest( dest, block ) dest, ret = HTTP.procdest( dest, block )
unless @entity then unless @body then
@entity = @command.get_body( response, dest ) @body = @command.get_body( response, dest )
end end
@entity @body
end end
alias body entity alias entity body
def off def off
entity body
@command = nil @command = nil
end end
end end
class HTTPSwitchProtocol < SuccessCode; end class HTTPResponse < Response
class HTTPOK < SuccessCode; end def initialize( code_type, code, msg )
class HTTPCreated < SuccessCode; end super
class HTTPAccepted < SuccessCode; end @data = {}
class HTTPNonAuthoritativeInformation < SuccessCode; end @http_body_exist = true
class HTTPNoContent < SuccessCode; end end
class HTTPResetContent < SuccessCode; end
class HTTPPartialContent < SuccessCode; end
class HTTPMultipleChoice < RetryCode; end attr_accessor :http_body_exist
class HTTPMovedPermanently < RetryCode; end
class HTTPMovedTemporarily < RetryCode; end def []( key )
class HTTPNotModified < RetryCode; end @data[ key.downcase ]
class HTTPUseProxy < RetryCode; end 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
HTTPOK = HTTPSuccessCode.mkchild
HTTPCreated = HTTPSuccessCode.mkchild
HTTPAccepted = HTTPSuccessCode.mkchild
HTTPNonAuthoritativeInformation = HTTPSuccessCode.mkchild
HTTPNoContent = HTTPSuccessCode.mkchild
HTTPResetContent = HTTPSuccessCode.mkchild
HTTPPartialContent = HTTPSuccessCode.mkchild
HTTPMultipleChoice = HTTPRetriableCode.mkchild
HTTPMovedPermanently = HTTPRetriableCode.mkchild
HTTPMovedTemporarily = HTTPRetriableCode.mkchild
HTTPNotModified = HTTPRetriableCode.mkchild
HTTPUseProxy = HTTPRetriableCode.mkchild
class HTTPBadRequest < RetryCode; end HTTPBadRequest = HTTPRetriableCode.mkchild
class HTTPUnauthorized < RetryCode; end HTTPUnauthorized = HTTPRetriableCode.mkchild
class HTTPPaymentRequired < RetryCode; end HTTPPaymentRequired = HTTPRetriableCode.mkchild
class HTTPForbidden < FatalErrorCode; end HTTPForbidden = HTTPFatalErrorCode.mkchild
class HTTPNotFound < FatalErrorCode; end HTTPNotFound = HTTPFatalErrorCode.mkchild
class HTTPMethodNotAllowed < FatalErrorCode; end HTTPMethodNotAllowed = HTTPFatalErrorCode.mkchild
class HTTPNotAcceptable < FatalErrorCode; end HTTPNotAcceptable = HTTPFatalErrorCode.mkchild
class HTTPProxyAuthenticationRequired < RetryCode; end HTTPProxyAuthenticationRequired = HTTPRetriableCode.mkchild
class HTTPRequestTimeOut < FatalErrorCode; end HTTPRequestTimeOut = HTTPFatalErrorCode.mkchild
class HTTPConflict < FatalErrorCode; end HTTPConflict = HTTPFatalErrorCode.mkchild
class HTTPGone < FatalErrorCode; end HTTPGone = HTTPFatalErrorCode.mkchild
class HTTPLengthRequired < FatalErrorCode; end HTTPLengthRequired = HTTPFatalErrorCode.mkchild
class HTTPPreconditionFailed < FatalErrorCode; end HTTPPreconditionFailed = HTTPFatalErrorCode.mkchild
class HTTPRequestEntityTooLarge < FatalErrorCode; end HTTPRequestEntityTooLarge = HTTPFatalErrorCode.mkchild
class HTTPRequestURITooLarge < FatalErrorCode; end HTTPRequestURITooLarge = HTTPFatalErrorCode.mkchild
class HTTPUnsupportedMediaType < FatalErrorCode; end HTTPUnsupportedMediaType = HTTPFatalErrorCode.mkchild
class HTTPNotImplemented < FatalErrorCode; end HTTPNotImplemented = HTTPFatalErrorCode.mkchild
class HTTPBadGateway < FatalErrorCode; end HTTPBadGateway = HTTPFatalErrorCode.mkchild
class HTTPServiceUnavailable < FatalErrorCode; end HTTPServiceUnavailable = HTTPFatalErrorCode.mkchild
class HTTPGatewayTimeOut < FatalErrorCode; end HTTPGatewayTimeOut = HTTPFatalErrorCode.mkchild
class HTTPVersionNotSupported < FatalErrorCode; end HTTPVersionNotSupported = HTTPFatalErrorCode.mkchild
class HTTPCommand < Command class HTTPCommand < Command
@ -431,38 +464,48 @@ class HTTPBadResponse < HTTPError; end
def get_response def get_response
rep = get_reply resp = get_reply
rep = get_reply while ContinueCode === rep resp = get_reply while ContinueCode === resp
header = {}
while true do while true do
line = @socket.readline line = @socket.readline
break if line.empty? break if line.empty?
nm = /\A[^:]+/.match( line )[0].strip.downcase
header[nm] = line
end
rep['http-header'] = header
rep 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
resp
end end
def check_response( resp ) def check_response( resp )
reply_must resp, SuccessCode reply_must resp, SuccessCode
end end
def get_body( rep, dest ) def get_body( resp, dest )
header = rep['http-header'] if resp.http_body_exist then
if chunked? resp then
if rep['body-exist'] then read_chunked( dest, resp )
if chunked? header then
read_chunked( dest, header )
else else
if clen = content_length( header ) then clen = content_length( resp )
if clen then
@socket.read clen, dest @socket.read clen, dest
else else
if false then # "multipart/byteranges" check should be done clen = range_length( resp )
if clen then
@socket.read clen, dest
else else
if header['Connection'] and tmp = resp['connection']
/connection:\s*close/i === header['Connection'] then if tmp and /close/i === tmp then
@socket.read_all dest @socket.read_all dest
@socket.close @socket.close
end end
@ -471,7 +514,7 @@ class HTTPBadResponse < HTTPError; end
end end
end end
end_critical end_critical
reply_must rep, SuccessCode reply_must resp, SuccessCode
dest dest
end end
@ -501,7 +544,7 @@ class HTTPBadResponse < HTTPError; end
end end
CODE_TO_CLASS = { HTTPCODE_TO_OBJ = {
'100' => [ContinueCode, false], '100' => [ContinueCode, false],
'100' => [HTTPSwitchProtocol, false], '100' => [HTTPSwitchProtocol, false],
@ -547,17 +590,18 @@ class HTTPBadResponse < HTTPError; end
def get_reply def get_reply
str = @socket.readline 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}" raise HTTPBadResponse, "wrong status line format: #{str}"
end end
@http_version = $1 @http_version = m[1]
status = $2 status = m[2]
discrip = $3 discrip = m[3]
klass, bodyexist = CODE_TO_CLASS[status] || [UnknownCode, true] klass, bodyexist = HTTPCODE_TO_OBJ[status] || [UnknownCode, true]
code = klass.new( status, discrip ) resp = HTTPResponse.new( klass, status, discrip )
code['body-exist'] = bodyexist resp.http_body_exist = bodyexist
code resp
end end
def read_chunked( ret, header ) def read_chunked( ret, header )
@ -567,10 +611,11 @@ class HTTPBadResponse < HTTPError; end
while true do while true do
line = @socket.readline 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" raise HTTPBadResponse, "chunk size not given"
end end
len = $&.hex len = m[0].hex
break if len == 0 break if len == 0
@socket.read( len, ret ); total += len @socket.read( len, ret ); total += len
@socket.read 2 # \r\n @socket.read 2 # \r\n
@ -581,28 +626,47 @@ class HTTPBadResponse < HTTPError; end
end end
header.delete 'transfer-encoding' header.delete 'transfer-encoding'
header[ 'content-length' ] = "Content-Length: #{total}" header[ 'content-length' ] = total.to_s
end end
def content_length( header ) def content_length( header )
unless str = header[ 'content-length' ] then if header.key? 'content-length' then
return nil m = /\d+/.match( header['content-length'] )
unless m then
raise HTTPBadResponse, 'wrong Content-Length format'
end
m[0].to_i
else
nil
end end
unless /\Acontent-length:\s*(\d+)/i === str then
raise HTTPBadResponse, "content-length format error"
end
$1.to_i
end end
def chunked?( header ) def chunked?( header )
if str = header[ 'transfer-encoding' ] then str = header[ 'transfer-encoding' ]
if /\Atransfer-encoding:\s*chunked/i === str then if str and /(\A|\s+)chunked(?:\s+|\z)/i === str then
return true true
end else
false
end 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
end end

Просмотреть файл

@ -314,9 +314,9 @@ Net::POP3
str = @socket.readline str = @socket.readline
if /\A\+/ === str then 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 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
end end

Просмотреть файл

@ -15,7 +15,7 @@ require 'socket'
module Net module Net
Version = '1.1.11' Version = '1.1.12'
=begin =begin
@ -95,7 +95,7 @@ Object
@port = port @port = port
end end
def connect( addr, port ) def connect( addr = nil, port = nil )
super @proxyaddr, @proxyport super @proxyaddr, @proxyport
end end
private :connect private :connect
@ -286,55 +286,21 @@ Object
end end
class ProtocolError < StandardError ; end class Response
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 ReplyCode def initialize( ctype, cno, msg )
@code_type = ctype
class << self @code = cno
@message = msg
def error_type( err ) super()
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
end end
attr_reader :code_type, :code, :message
alias msg message
def error!( sending ) def error!( sending )
mes = <<MES raise @code_type.error_type,
sprintf( <<MSG, @code, Net.quote(sending), Net.quote(@message) )
status %s status %s
writing string is: writing string is:
@ -342,43 +308,58 @@ writing string is:
error message from server is: error message from server is:
%s %s
MES MSG
type.error! sprintf( mes, @code, Net.quote(sending), Net.quote(@msg) )
end end
end end
class SuccessCode < ReplyCode
error_type ProtoUnknownError
end
class ContinueCode < SuccessCode class ProtocolError < StandardError; end
error_type ProtoUnknownError class ProtoSyntaxError < ProtocolError; end
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 class Code
error_type ProtoSyntaxError
end
class FatalErrorCode < ErrorCode def initialize( paren, err )
error_type ProtoFatalError @parents = paren
end @err = err
class ServerBusyCode < ErrorCode @parents.push self
error_type ProtoServerError end
end
class RetryCode < ReplyCode attr_reader :parents
error_type ProtoRetryError
end
class UnknownCode < ReplyCode def error_type
error_type ProtoUnknownError @err
end
def ===( response )
response.code_type.parents.reverse_each {|i| return true if i == self }
false
end
def mkchild( err = nil )
type.new( @parents + [self], err || @err )
end
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 @addr = addr
@port = port @port = port
@pipe = pipe @pipe = pipe
@prepipe = nil
@closed = true @closed = true
@ipaddr = '' @ipaddr = ''
@ -471,47 +453,49 @@ MES
TERMEXP = /\n|\r\n|\r/o TERMEXP = /\n|\r\n|\r/o
def read( len, ret = '' ) def read( len, dest = '' )
@pipe << "reading #{len} bytes...\n" if pre = @pipe ; @pipe = nil @pipe << "reading #{len} bytes...\n" if @pipe; pipeoff
rsize = 0 rsize = 0
while rsize + @buffer.size < len do while rsize + @buffer.size < len do
rsize += writeinto( ret, @buffer.size ) rsize += writeinto( dest, @buffer.size )
fill_rbuf fill_rbuf
end end
writeinto( ret, len - rsize ) writeinto( dest, len - rsize )
@pipe << "read #{len} bytes\n" if @pipe = pre @pipe << "read #{len} bytes\n" if pipeon
ret dest
end end
def read_all( ret = '' ) def read_all( dest = '' )
@pipe << "reading all...\n" if pre = @pipe; @pipe = nil @pipe << "reading all...\n" if @pipe; pipeoff
rsize = 0 rsize = 0
begin begin
while true do while true do
rsize += writeinto( ret, @buffer.size ) rsize += writeinto( dest, @buffer.size )
fill_rbuf fill_rbuf
end end
rescue EOFError rescue EOFError
; ;
end end
@pipe << "read #{rsize} bytes\n" if @pipe = pre @pipe << "read #{rsize} bytes\n" if pipeon
ret dest
end end
def readuntil( target ) def readuntil( target )
until idx = @buffer.index( target ) do while true do
idx = @buffer.index( target )
break if idx
fill_rbuf fill_rbuf
end end
ret = '' dest = ''
writeinto( ret, idx + target.size ) writeinto( dest, idx + target.size )
ret dest
end end
@ -522,8 +506,8 @@ MES
end end
def read_pendstr( dest = '' ) def read_pendstr( dest )
@pipe << "reading text...\n" if pre = @pipe ; @pipe = nil @pipe << "reading text...\n" if @pipe; pipeoff
rsize = 0 rsize = 0
@ -533,17 +517,16 @@ MES
dest << str dest << str
end end
@pipe << "read #{rsize} bytes\n" if @pipe = pre @pipe << "read #{rsize} bytes\n" if pipeon
dest dest
end end
def read_pendlist def read_pendlist
@pipe << "reading list...\n" if pre = @pipe ; @pipe = nil @pipe << "reading list...\n" if @pipe; pipeoff
arr = [] arr = []
str = nil str = nil
call = iterator?
while (str = readuntil( CRLF )) != D_CRLF do while (str = readuntil( CRLF )) != D_CRLF do
str.chop! str.chop!
@ -551,7 +534,7 @@ MES
yield str if iterator? yield str if iterator?
end end
@pipe << "read #{arr.size} lines\n" if @pipe = pre @pipe << "read #{arr.size} lines\n" if pipeon
arr arr
end end
@ -565,12 +548,12 @@ MES
@buffer << @socket.sysread( READ_BLOCK ) @buffer << @socket.sysread( READ_BLOCK )
end end
def writeinto( ret, len ) def writeinto( dest, len )
bsi = @buffer.size bsi = @buffer.size
ret << @buffer[ 0, len ] dest << @buffer[ 0, len ]
@buffer = @buffer[ len, bsi - len ] @buffer = @buffer[ len, bsi - len ]
@pipe << %{read "#{Net.quote ret}"\n} if @pipe @pipe << %{read "#{Net.quote dest}"\n} if @pipe
len len
end end
@ -593,7 +576,7 @@ MES
end end
def write_bin( src, block = nil ) def write_bin( src, block )
do_write_beg do_write_beg
if block then if block then
block.call WriteAdapter.new( self, :do_write_do ) block.call WriteAdapter.new( self, :do_write_do )
@ -606,12 +589,12 @@ MES
end end
def write_pendstr( src ) def write_pendstr( src, block )
@pipe << "writing text from #{src.type}\n" if pre = @pipe ; @pipe = nil @pipe << "writing text from #{src.type}\n" if @pipe; pipeoff
do_write_beg do_write_beg
if iterator? then if block then
yield WriteAdapter.new( self, :write_pendstr_inner ) block.call WriteAdapter.new( self, :write_pendstr_inner )
else else
write_pendstr_inner src write_pendstr_inner src
end end
@ -619,7 +602,7 @@ MES
do_write_do D_CRLF do_write_do D_CRLF
wsize = do_write_fin wsize = do_write_fin
@pipe << "wrote #{wsize} bytes text" if @pipe = pre @pipe << "wrote #{wsize} bytes text" if pipeon
wsize wsize
end end
@ -649,11 +632,13 @@ MES
adding( src ) do adding( src ) do
beg = 0 beg = 0
buf = @wbuf buf = @wbuf
while pos = buf.index( TERMEXP, beg ) do while true do
pos = buf.index( TERMEXP, beg )
break unless pos
s = $&.size s = $&.size
break if pos + s == buf.size - 1 and buf[-1] == ?\r 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 beg = pos + s
end end
@wbuf = buf[ beg, buf.size - beg ] if beg != 0 @wbuf = buf[ beg, buf.size - beg ] if beg != 0
@ -671,7 +656,9 @@ MES
end end
when File when File
while i = src.read( 512 ) do while true do
i = src.read( 512 )
break unless i
@wbuf << i @wbuf << i
yield yield
end end
@ -691,8 +678,10 @@ MES
buf << "\n" unless /\n|\r/o === buf[-1,1] buf << "\n" unless /\n|\r/o === buf[-1,1]
beg = 0 beg = 0
while pos = buf.index( TERMEXP, beg ) do while true do
send mid, buf[ beg, pos - beg ] << CRLF pos = buf.index( TERMEXP, beg )
break unless pos
__send__ mid, buf[ beg, pos - beg ] << CRLF
beg = pos + $&.size beg = pos + $&.size
end end
end end
@ -727,6 +716,19 @@ MES
@writtensize @writtensize
end end
def pipeoff
@prepipe = @pipe
@pipe = nil
@prepipe
end
def pipeon
@pipe = @prepipe
@prepipe = nil
@pipe
end
end end

Просмотреть файл

@ -76,12 +76,12 @@ Net::Protocol
def sendmail( mailsrc, fromaddr, toaddrs ) def sendmail( mailsrc, fromaddr, toaddrs )
do_ready fromaddr, toaddrs do_ready fromaddr, toaddrs
@command.write_mail mailsrc @command.write_mail mailsrc, nil
end end
def ready( fromaddr, toaddrs, &block ) def ready( fromaddr, toaddrs, &block )
do_ready fromaddr, toaddrs do_ready fromaddr, toaddrs
@command.write_mail( &block ) @command.write_mail nil, block
end end
@ -163,8 +163,8 @@ Net::Protocol
end end
def write_mail( mailsrc = nil, &block ) def write_mail( mailsrc, block )
@socket.write_pendstr mailsrc, &block @socket.write_pendstr mailsrc, block
check_reply SuccessCode check_reply SuccessCode
end_critical end_critical
end end
@ -189,7 +189,7 @@ Net::Protocol
klass = case stat[0] klass = case stat[0]
when ?2 then SuccessCode when ?2 then SuccessCode
when ?3 then ContinueCode when ?3 then ContinueCode
when ?4 then ServerBusyCode when ?4 then ServerErrorCode
when ?5 then when ?5 then
case stat[1] case stat[1]
when ?0 then SyntaxErrorCode when ?0 then SyntaxErrorCode
@ -197,7 +197,7 @@ Net::Protocol
end end
end end
klass.new( stat, arr.join('') ) Response.new( klass, stat, arr.join('') )
end end