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
: get( path, header = nil, ret = '' )
: get( path, header = nil, dest = '' )
: get( path, header = nil ) {|str| .... }
get data from "path" on connecting host.
"header" is a Hash like { 'Accept' => '*/*', ... }.
The data will be written to "ret" using "<<" method.
This method returns response header (Hash) and "ret".
"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.
: head( path, header = nil )
get only header from "path" on connecting host.
@ -53,6 +56,30 @@ class HTTPBadResponse < HTTPError; end
'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
class HTTP < Protocol
@ -61,19 +88,71 @@ class HTTPBadResponse < HTTPError; end
protocol_param :command_type, '::Net::HTTPCommand'
def get( path, u_header = nil, ret = '' )
def get( path, u_header = nil, dest = nil, &block )
u_header ||= {}
header = connecting( u_header ) {
@command.get ret, edit_path(path), u_header
if block then
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
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 ||= {}
header = connecting( u_header ) {
@command.head edit_path(path), u_header
if block then
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
@ -83,30 +162,51 @@ class HTTPBadResponse < HTTPError; end
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
def do_finish
unless @socket.closed? then
@command.head '/', { 'Connection' => 'Close' }
begin
@command.head '/', { 'Connection' => 'Close' }
rescue EOFError
end
end
end
def connecting( u_header )
def connecting( u_header, putp = false )
u_header = procheader( u_header )
ensure_connection u_header
yield
ensure_termination u_header
end
def ensure_connection( u_header )
if not @socket then
u_header['Connection'] = 'Close'
start
elsif @socket.closed? then
@socket.reopen
end
end
header = yield
def ensure_termination( u_header )
unless keep_alive? u_header then
@socket.close
end
header
@u_header = @response = nil
end
def keep_alive?( header )
@ -155,6 +255,20 @@ 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 HTTPMultipleChoiceCode < RetryCode; end
class HTTPMovedPermanentlyCode < RetryCode; end
class HTTPMovedTemporarilyCode < RetryCode; end
class HTTPNotModifiedCode < RetryCode; end
class HTTPUseProxyCode < RetryCode; end
class HTTPCommand < Command
HTTPVersion = '1.1'
@ -173,41 +287,26 @@ class HTTPBadResponse < HTTPError; end
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
clen = read_chunked_body( ret )
header.delete 'transfer-encoding'
header[ 'content-length' ] = "Content-Length: #{clen}"
else
if clen = content_length( header ) then
@socket.read clen, ret
else
@socket.read_all ret
end
end
header
def get( path, u_header )
request sprintf('GET %s HTTP/%s', path, HTTPVersion), u_header
end
def head( path, u_header = nil )
get_response sprintf( 'HEAD %s HTTP/%s', path, HTTPVersion ), u_header
def head( path, u_header )
request sprintf('HEAD %s HTTP/%s', path, HTTPVersion), u_header
end
# not work
def post( path, u_header = nil )
get_response sprintf( 'POST %s HTTP/%s', path, HTTPVersion ), u_header
def post( path, u_header, data )
request sprintf('POST %s HTTP/%s', path, HTTPVersion), u_header
@socket.write data
end
# not work
def put( path, u_header = nil )
get_response sprintf( 'PUT %s HTTP/%s', path, HTTPVersion ), u_header
def put( path, u_header, src )
request sprintf('PUT %s HTTP/%s', path, HTTPVersion), u_header
@socket.write_bin src
end
# def delete
# def trace
@ -215,19 +314,64 @@ class HTTPBadResponse < HTTPError; end
# 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
def get_response( line, u_header )
@socket.writeline line
write_header u_header
rep = get_reply
header = read_header
reply_must rep, SuccessCode
header
def request( req, u_header )
@socket.writeline req
if u_header then
header = @in_header.dup.update( u_header )
else
header = @in_header
end
header.each do |n,v|
@socket.writeline n + ': ' + v
end
@socket.writeline ''
end
def get_reply
str = @socket.readline
unless /\AHTTP\/(\d+\.\d+)?\s+(\d\d\d)\s*(.*)\z/i === str then
@ -237,20 +381,66 @@ 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 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
end
when ?2 then SuccessCode
when ?3 then RetryCode
when ?4 then ServerBusyCode
when ?5 then FatalErrorCode
else UnknownCode
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
@ -274,63 +464,6 @@ class HTTPBadResponse < HTTPError; end
false
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

View file

@ -216,66 +216,6 @@ Net::POP3
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
@ -371,22 +311,6 @@ Net::Command
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

View file

@ -15,7 +15,7 @@ require 'socket'
module Net
Version = '1.1.7'
Version = '1.1.9'
=begin
@ -219,27 +219,6 @@ Object
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
@ -317,10 +296,26 @@ Object
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
def error!( sending )
mes = <<MES
@ -370,78 +365,6 @@ MES
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
@ -639,6 +562,13 @@ Object
public
def write( str )
do_write_beg
do_write_do str
do_write_fin
end
def writeline( str )
do_write_beg
do_write_do str
@ -647,10 +577,10 @@ Object
end
def writebin( src )
def write_bin( src, block = nil )
do_write_beg
if iterator? then
yield WriteAdapter.new( self, :do_write_do )
if block then
block.call WriteAdapter.new( self, :do_write_do )
else
src.each do |bin|
do_write_do bin
@ -660,18 +590,6 @@ Object
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 )
@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'
def sendmail( mailsrc, fromaddr, toaddrs, &block )
@command.mailfrom fromaddr
@command.rcpt toaddrs
@command.data
@command.write_mail( mailsrc, &block )
def sendmail( mailsrc, fromaddr, toaddrs )
do_ready fromaddr, toaddrs
@command.write_mail mailsrc
end
def ready( fromaddr, toaddrs, &block )
sendmail nil, fromaddr, toaddrs, &block
do_ready fromaddr, toaddrs
@command.write_mail( &block )
end
@ -92,6 +91,12 @@ Net::Protocol
private
def do_ready( fromaddr, toaddrs )
@command.mailfrom fromaddr
@command.rcpt toaddrs
@command.data
end
def do_start( helodom = ENV['HOSTNAME'] )
unless helodom then
raise ArgumentError, "cannot get hostname"
@ -111,48 +116,6 @@ Net::Protocol
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
@ -189,7 +152,7 @@ Net::Command
end
def write_mail( mailsrc, &block )
def write_mail( mailsrc = nil, &block )
@socket.write_pendstr mailsrc, &block
check_reply SuccessCode
end