1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

o protocol.rb: version 1.1.9

o  smtp.rb:  arguments discription of do_ready was wrongly void


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@654 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
aamine 2000-03-26 08:48:15 +00:00
parent 688169fd83
commit d8d148d816
4 changed files with 285 additions and 347 deletions

View file

@ -38,11 +38,14 @@ class HTTPBadResponse < HTTPError; end
== Methods == Methods
: get( path, header = nil, ret = '' ) : get( path, header = nil, dest = '' )
: get( path, header = nil ) {|str| .... }
get data from "path" on connecting host. get data from "path" on connecting host.
"header" is a Hash like { 'Accept' => '*/*', ... }. "header" must be a Hash like { 'Accept' => '*/*', ... }.
The data will be written to "ret" using "<<" method. Data is written to "dest" by using "<<" method.
This method returns response header (Hash) and "ret". This method returns response header (Hash) and "dest".
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.
@ -53,6 +56,30 @@ class HTTPBadResponse < HTTPError; end
'content-type' => 'Content-Type: text/html', 'content-type' => 'Content-Type: text/html',
... } ... }
: post( path, data, header = nil, dest = '' )
: post( path, data, header = nil ) {|str| .... }
post "data"(must be String now) to "path" (and get entity body).
"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
: get2( path, header = nil )
send GET request for "path".
"header" must be a Hash like { 'Accept' => '*/*', ... }.
This method returns response header (Hash).
: 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, give a part String of entity body.
=end =end
class HTTP < Protocol class HTTP < Protocol
@ -61,19 +88,71 @@ class HTTPBadResponse < HTTPError; end
protocol_param :command_type, '::Net::HTTPCommand' protocol_param :command_type, '::Net::HTTPCommand'
def get( path, u_header = nil, ret = '' ) def get( path, u_header = nil, dest = nil, &block )
u_header ||= {} u_header ||= {}
header = connecting( u_header ) { if block then
@command.get ret, edit_path(path), u_header dest = ReadAdapter.new( block )
ret = nil
else
dest = ret = ''
end
resp = nil
connecting( u_header ) {
@command.get edit_path(path), u_header
resp = @command.get_response
@command.try_get_body( resp, dest )
} }
return header, ret return resp['http-header'], ret
end end
def head( path, u_header = nil ) def get2( path, u_header = {} )
only_header( :get, path, u_header )
end
def get_body( dest = '', &block )
if block then
dest = ReadAdapter.new( block )
end
@command.try_get_body @response, dest
ensure_termination @u_header
dest
end
def head( path, u_header = {} )
ret = only_header( :head, path, u_header )['http-header']
ensure_termination u_header
ret
end
def post( path, data, u_header = nil, dest = nil, &block )
u_header ||= {} u_header ||= {}
header = connecting( u_header ) { if block then
@command.head edit_path(path), u_header dest = ReadAdapter.new( block )
ret = nil
else
dest = ret = ''
end
resp = nil
connecting( u_header, true ) {
@command.post path, u_header, data
resp = @command.get_response
@command.try_get_body( resp, dest )
}
return resp['http-header'], ret
end
def post2( path, data, u_header = {} )
only_header :post, path, u_header, data
end
# not tested because I could not setup apache (__;;;
def put( path, src = nil, u_header = {}, &block )
u_header ||= u_header
connecting( u_header, true ) {
@command.put path, u_header, src, dest
} }
header header
@ -83,30 +162,51 @@ class HTTPBadResponse < HTTPError; end
private private
def only_header( mid, path, u_header, data = nil )
@u_header = u_header ? procheader(u_header) : {}
@response = nil
ensure_connection @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
# called when connecting # called when connecting
def do_finish def do_finish
unless @socket.closed? then unless @socket.closed? then
@command.head '/', { 'Connection' => 'Close' } begin
@command.head '/', { 'Connection' => 'Close' }
rescue EOFError
end
end end
end end
def connecting( u_header ) def connecting( u_header, putp = false )
u_header = procheader( u_header ) u_header = procheader( u_header )
ensure_connection u_header
yield
ensure_termination u_header
end
def ensure_connection( u_header )
if not @socket then if not @socket then
u_header['Connection'] = 'Close' u_header['Connection'] = 'Close'
start start
elsif @socket.closed? then elsif @socket.closed? then
@socket.reopen @socket.reopen
end end
end
header = yield def ensure_termination( u_header )
unless keep_alive? u_header then unless keep_alive? u_header then
@socket.close @socket.close
end end
@u_header = @response = nil
header
end end
def keep_alive?( header ) def keep_alive?( header )
@ -155,6 +255,20 @@ class HTTPBadResponse < HTTPError; end
HTTPSession = HTTP 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 HTTPMultipleChoiceCode < RetryCode; end
class HTTPMovedPermanentlyCode < RetryCode; end
class HTTPMovedTemporarilyCode < RetryCode; end
class HTTPNotModifiedCode < RetryCode; end
class HTTPUseProxyCode < RetryCode; end
class HTTPCommand < Command class HTTPCommand < Command
HTTPVersion = '1.1' HTTPVersion = '1.1'
@ -173,40 +287,25 @@ class HTTPBadResponse < HTTPError; end
attr_reader :http_version attr_reader :http_version
def get( ret, path, u_header = nil )
header = get_response(
sprintf( 'GET %s HTTP/%s', path, HTTPVersion ), u_header )
if chunked? header then def get( path, u_header )
clen = read_chunked_body( ret ) request sprintf('GET %s HTTP/%s', path, HTTPVersion), u_header
header.delete 'transfer-encoding' end
header[ 'content-length' ] = "Content-Length: #{clen}"
else def head( path, u_header )
if clen = content_length( header ) then request sprintf('HEAD %s HTTP/%s', path, HTTPVersion), u_header
@socket.read clen, ret
else
@socket.read_all ret
end
end
header
end end
def post( path, u_header, data )
def head( path, u_header = nil ) request sprintf('POST %s HTTP/%s', path, HTTPVersion), u_header
get_response sprintf( 'HEAD %s HTTP/%s', path, HTTPVersion ), u_header @socket.write data
end end
def put( path, u_header, src )
# not work request sprintf('PUT %s HTTP/%s', path, HTTPVersion), u_header
def post( path, u_header = nil ) @socket.write_bin src
get_response sprintf( 'POST %s HTTP/%s', path, HTTPVersion ), u_header
end end
# not work
def put( path, u_header = nil )
get_response sprintf( 'PUT %s HTTP/%s', path, HTTPVersion ), u_header
end
# def delete # def delete
@ -215,19 +314,64 @@ class HTTPBadResponse < HTTPError; end
# def options # def options
def get_response
rep = get_reply
rep = get_reply while ContinueCode === rep
header = {}
while true do
line = @socket.readline
break if line.empty?
nm = /\A[^:]+/.match( line )[0].strip.downcase
header[nm] = line
end
rep['http-header'] = header
reply_must rep, SuccessCode
rep
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/bytelenges" check should be done here ...
###
@socket.read_all dest
end
end
end
def try_get_body( rep, dest )
rep = get_reply while ContinueCode === rep
return nil unless rep['body-exist']
get_body rep, dest
end
private private
def get_response( line, u_header ) def request( req, u_header )
@socket.writeline line @socket.writeline req
write_header u_header if u_header then
rep = get_reply header = @in_header.dup.update( u_header )
header = read_header else
reply_must rep, SuccessCode header = @in_header
end
header header.each do |n,v|
@socket.writeline n + ': ' + v
end
@socket.writeline ''
end 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 unless /\AHTTP\/(\d+\.\d+)?\s+(\d\d\d)\s*(.*)\z/i === str then
@ -237,20 +381,66 @@ class HTTPBadResponse < HTTPError; end
status = $2 status = $2
discrip = $3 discrip = $3
be = false
klass = case status[0] klass = case status[0]
when ?1 then when ?1 then
case status[2] case status[2]
when ?0 then ContinueCode when ?0 then ContinueCode
when ?1 then SuccessCode 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 else UnknownCode
end end
when ?2 then SuccessCode
when ?3 then RetryCode
when ?4 then ServerBusyCode when ?4 then ServerBusyCode
when ?5 then FatalErrorCode when ?5 then FatalErrorCode
else UnknownCode else UnknownCode
end end
klass.new( status, discrip ) code = klass.new( status, discrip )
code['body-exist'] = be
code
end
def read_chunked( ret, header )
line = nil
len = nil
total = 0
while true do
line = @socket.readline
unless /[0-9a-hA-H]+/ === line then
raise HTTPBadResponse, "chunk size not given"
end
len = $&.hex
break if len == 0
@socket.read( len, ret ); total += len
@socket.read 2 # \r\n
end
while true do
line = @socket.readline
break if line.empty?
end
header.delete 'transfer-encoding'
header[ 'content-length' ] = "Content-Length: #{total}"
end end
@ -274,63 +464,6 @@ class HTTPBadResponse < HTTPError; end
false false
end end
def read_header
header = {}
while true do
line = @socket.readline
break if line.empty?
/\A[^:]+/ === line
nm = $&
nm.strip!
nm.downcase!
header[ nm ] = line
end
header
end
def write_header( user )
if user then
header = @in_header.dup.update user
else
header = @in_header
end
header.each do |n,v|
@socket.writeline n + ': ' + v
end
@socket.writeline ''
if tmp = header['Connection'] then
/close/i === tmp
else
false
end
end
def read_chunked_body( ret )
line = nil
len = nil
total = 0
while true do
line = @socket.readline
unless /[0-9a-hA-H]+/ === line then
raise HTTPBadResponse, "chunk size not given"
end
len = $&.hex
break if len == 0
@socket.read( len, ret ); total += len
@socket.read 2 # \r\n
end
while true do
line = @socket.readline
break if line.empty?
end
total
end
end end

View file

@ -216,66 +216,6 @@ Net::POP3
APOPSession = APOP APOPSession = APOP
=begin
== Net::POP3Command
POP3 command class.
=== Super Class
Net::Command
=== Class Methods
: new( socket )
This method creates new POP3Command object. 'socket' must be ProtocolSocket.
=== Methods
: auth( account, password )
This method do POP authorization (no RPOP)
In case of failed authorization, raises Protocol::ProtocolError exception.
: list
a list of mails which existing on server.
The list is an array like "array[ number ] = size".
ex:
The list from server is
1 2452
2 3355
4 9842
:
then, an array is
[ nil, 2452, 3355, nil, 9842, ... ]
: quit
This method ends POP using 'QUIT' commmand.
: rset
This method reset all changes done in current session,
by sending 'RSET' command.
: top( num, lines = 0 )
This method gets all mail header and 'lines' lines body
by sending 'TOP' command. 'num' is mail number.
WARNING: the TOP command is 'Optional' in RFC1939 (POP3)
: retr( num : Integer )
This method gets a mail by 'RETR' command. 'num' is mail number.
: dele( num : Integer )
This method deletes a mail on server by 'DELE'.
=end
class POP3Command < Command class POP3Command < Command
@ -371,22 +311,6 @@ Net::Command
end end
=begin
== APOPCommand
=== Super Class
POP3Command
=== Methods
: auth( account, password )
This method do authorization by sending 'APOP' command.
If server is not APOP server, this raises Net::ProtoAuthError exception.
On other errors, raises Net::ProtocolError.
=end
class APOPCommand < POP3Command class APOPCommand < POP3Command

View file

@ -15,7 +15,7 @@ require 'socket'
module Net module Net
Version = '1.1.7' Version = '1.1.9'
=begin =begin
@ -219,27 +219,6 @@ Object
Session = Protocol Session = Protocol
=begin
== Net::Command
=== Super Class
Object
=== Class Methods
: new( socket )
This method create new Command object. 'socket' must be ProtocolSocket.
This method is abstract class.
=== Methods
: quit
This method dispatch command which ends the protocol.
=end
class Command class Command
@ -317,10 +296,26 @@ Object
def initialize( cod, mes ) def initialize( cod, mes )
@code = cod @code = cod
@msg = mes @msg = mes
@data = nil
end end
attr_reader :code, :msg 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
def error!( sending ) def error!( sending )
mes = <<MES mes = <<MES
@ -370,78 +365,6 @@ MES
end end
=begin
== Net::ProtocolSocket
=== Super Class
Object
=== Class Methods
: new( address = 'localhost', port = nil )
This create new ProtocolSocket object, and connect to server.
=== Methods
: close
This method closes socket.
: address, addr
a FQDN address of server
: ip_address, ipaddr
an IP address of server
: port
connecting port number.
: closed?
true if ProtocolSokcet have been closed already
: read( length )
This method read 'length' bytes and return the string.
: readuntil( target )
This method read until find 'target'. Returns read string.
: readline
read until "\r\n" and returns it without "\r\n".
: read_pendstr
This method read until "\r\n.\r\n".
At the same time, delete period at line head and final line ("\r\n.\r\n").
: read_pendlist
: read_pendlist{|line| .... }
This method read until "\r\n.\r\n". This method resembles to 'read_pendstr',
but 'read_pendlist' don't check period at line head, and returns array which
each element is one line.
When this method was called with block, evaluate it for each reading a line.
: write( src )
This method send 'src'. ProtocolSocket read strings from 'src' by 'each'
iterator. This method returns written bytes.
: writebin( src )
This method send 'src'. ProtocolSokcet read string from 'src' by 'each'
iterator. This method returns written bytes.
: writeline( str )
This method writes 'str'. There has not to be bare "\r" or "\n" in 'str'.
: write_pendstr( src )
This method writes 'src' as a mail.
ProtocolSocket reads strings from 'src' by 'each' iterator.
This returns written bytes.
=end
class WriteAdapter class WriteAdapter
@ -639,6 +562,13 @@ Object
public public
def write( str )
do_write_beg
do_write_do str
do_write_fin
end
def writeline( str ) def writeline( str )
do_write_beg do_write_beg
do_write_do str do_write_do str
@ -647,10 +577,10 @@ Object
end end
def writebin( src ) def write_bin( src, block = nil )
do_write_beg do_write_beg
if iterator? then if block then
yield WriteAdapter.new( self, :do_write_do ) block.call WriteAdapter.new( self, :do_write_do )
else else
src.each do |bin| src.each do |bin|
do_write_do bin do_write_do bin
@ -660,18 +590,6 @@ Object
end end
def write( src )
do_write_beg
if iterator? then
yield WriteAdapter.new( self, :write_inner )
else
write_inner src
end
each_crlf_line2( :i_w )
do_write_fin
end
def write_pendstr( src ) def write_pendstr( src )
@pipe << "writing text from #{src.type}\n" if pre = @pipe ; @pipe = nil @pipe << "writing text from #{src.type}\n" if pre = @pipe ; @pipe = nil

View file

@ -74,15 +74,14 @@ Net::Protocol
protocol_param :command_type, '::Net::SMTPCommand' protocol_param :command_type, '::Net::SMTPCommand'
def sendmail( mailsrc, fromaddr, toaddrs, &block ) def sendmail( mailsrc, fromaddr, toaddrs )
@command.mailfrom fromaddr do_ready fromaddr, toaddrs
@command.rcpt toaddrs @command.write_mail mailsrc
@command.data
@command.write_mail( mailsrc, &block )
end end
def ready( fromaddr, toaddrs, &block ) def ready( fromaddr, toaddrs, &block )
sendmail nil, fromaddr, toaddrs, &block do_ready fromaddr, toaddrs
@command.write_mail( &block )
end end
@ -92,6 +91,12 @@ Net::Protocol
private private
def do_ready( fromaddr, toaddrs )
@command.mailfrom fromaddr
@command.rcpt toaddrs
@command.data
end
def do_start( helodom = ENV['HOSTNAME'] ) def do_start( helodom = ENV['HOSTNAME'] )
unless helodom then unless helodom then
raise ArgumentError, "cannot get hostname" raise ArgumentError, "cannot get hostname"
@ -111,48 +116,6 @@ Net::Protocol
SMTPSession = SMTP SMTPSession = SMTP
=begin
== Net::SMTPCommand
=== Super Class
Net::Command
=== Class Methods
: new( socket )
This method creates new SMTPCommand object, and open SMTP.
=== Methods
: helo( helo_domain )
This method send "HELO" command and start SMTP.
helo_domain is localhost's FQDN.
: mailfrom( from_addr )
This method sends "MAIL FROM" command.
from_addr is your mail address (xxxx@xxxx)
: rcpt( to_addrs )
This method sends "RCPT TO" command.
to_addrs is array of mail address (xxxx@xxxx) of destination.
: data
This method sends "DATA" command.
: write_mail( mailsrc )
: write_mail {|socket| ... }
send 'mailsrc' as mail.
SMTPCommand reads strings from 'mailsrc' by calling 'each' iterator.
When iterator, SMTPCommand only stand by socket and pass it.
(The socket will accepts only 'in_write' method in the block)
: quit
This method sends "QUIT" command and ends SMTP session.
=end
class SMTPCommand < Command class SMTPCommand < Command
@ -189,7 +152,7 @@ Net::Command
end end
def write_mail( mailsrc, &block ) def write_mail( mailsrc = nil, &block )
@socket.write_pendstr mailsrc, &block @socket.write_pendstr mailsrc, &block
check_reply SuccessCode check_reply SuccessCode
end end