mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Net version 1.1.3
o http.rb rd o Session -> Protocol git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@596 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
0c00050f84
commit
a1d1b15167
4 changed files with 419 additions and 372 deletions
502
lib/net/http.rb
502
lib/net/http.rb
|
@ -5,6 +5,9 @@
|
|||
maintained by Minero Aoki <aamine@dp.u-netsurf.ne.jp>
|
||||
This file is derived from http-access.rb
|
||||
|
||||
This library is distributed under the terms of the Ruby license.
|
||||
You can freely distribute/modify this library.
|
||||
|
||||
=end
|
||||
|
||||
require 'net/session'
|
||||
|
@ -17,253 +20,296 @@ class HTTPError < ProtocolError; end
|
|||
class HTTPBadResponse < HTTPError; end
|
||||
|
||||
|
||||
class HTTPSession < Session
|
||||
=begin
|
||||
|
||||
Version = '1.1.2'
|
||||
= HTTP class
|
||||
|
||||
session_setvar :port, '80'
|
||||
session_setvar :command_type, 'Net::HTTPCommand'
|
||||
== Class Methods
|
||||
|
||||
|
||||
def get( path = '/', header = nil, ret = '' )
|
||||
confirm_connection
|
||||
@proto.get edit_path(path), header, ret
|
||||
end
|
||||
|
||||
def head( path = '/', header = nil )
|
||||
confirm_connection
|
||||
@proto.head edit_path(path), header
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
def confirm_connection
|
||||
if @socket.closed? then
|
||||
@socket.reopen
|
||||
end
|
||||
end
|
||||
: new( address, port = 80 )
|
||||
|
||||
def do_finish
|
||||
unless @proto.error_occured or @socket.closed? then
|
||||
head '/', { 'Connection' => 'Close' }
|
||||
create new HTTP object.
|
||||
|
||||
: port
|
||||
|
||||
returns HTTP default port, 80
|
||||
|
||||
: command_type
|
||||
|
||||
returns Command class, HTTPCommand
|
||||
|
||||
|
||||
== Methods
|
||||
|
||||
: get( path, header = nil, ret = '' )
|
||||
|
||||
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".
|
||||
|
||||
: 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
|
||||
|
||||
{ 'content-length' => 'Content-Length: 2554',
|
||||
'content-type' => 'Content-Type: text/html',
|
||||
... }
|
||||
|
||||
=end
|
||||
|
||||
class HTTP < Protocol
|
||||
|
||||
Version = '1.1.3'
|
||||
|
||||
protocol_param :port, '80'
|
||||
protocol_param :command_type, '::Net::HTTPCommand'
|
||||
|
||||
|
||||
def get( path, u_header = nil, ret = '' )
|
||||
header = connecting {
|
||||
@command.get ret, edit_path(path), u_header
|
||||
}
|
||||
return header, ret
|
||||
end
|
||||
|
||||
def head( path, u_header = nil )
|
||||
connecting {
|
||||
@command.head edit_path(path), u_header
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def edit_path( path )
|
||||
path
|
||||
end
|
||||
private
|
||||
|
||||
class << self
|
||||
def Proxy( addr, port )
|
||||
klass = super
|
||||
klass.module_eval %-
|
||||
def edit_path( path )
|
||||
'http://' + address + (port == self.port ? '' : ":\#{port}") + path
|
||||
|
||||
def connecting
|
||||
if @socket.closed? then
|
||||
@socket.reopen
|
||||
end
|
||||
header = yield
|
||||
@socket.close unless keep_alive? header
|
||||
|
||||
header
|
||||
end
|
||||
|
||||
def keep_alive?( header )
|
||||
if str = header[ 'connection' ] then
|
||||
if /\Aconnection:\s*keep-alive/i === str then
|
||||
return true
|
||||
end
|
||||
else
|
||||
if @http_version == '1.1' then
|
||||
return true
|
||||
end
|
||||
-
|
||||
klass
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
HTTP = HTTPSession
|
||||
|
||||
|
||||
class HTTPCommand < Command
|
||||
|
||||
HTTPVersion = '1.1'
|
||||
|
||||
def initialize( sock )
|
||||
@http_version = HTTPVersion
|
||||
|
||||
@in_header = {}
|
||||
@in_header[ 'Host' ] = sock.addr
|
||||
#@in_header[ 'User-Agent' ] = "Ruby http version #{HTTPSession::Version}"
|
||||
@in_header[ 'Connection' ] = 'keep-alive'
|
||||
@in_header[ 'Accept' ] = '*/*'
|
||||
|
||||
super sock
|
||||
end
|
||||
|
||||
|
||||
attr :http_version
|
||||
|
||||
def get( path, u_header = nil, ret = '' )
|
||||
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
|
||||
@socket.read content_length( header ), ret
|
||||
end
|
||||
@socket.close unless keep_alive? header
|
||||
|
||||
return header, ret
|
||||
end
|
||||
|
||||
|
||||
def head( path, u_header = nil )
|
||||
header = get_response(
|
||||
sprintf( 'HEAD %s HTTP/%s', path, HTTPVersion ), u_header )
|
||||
@socket.close unless keep_alive? header
|
||||
|
||||
header
|
||||
end
|
||||
|
||||
|
||||
# def put
|
||||
|
||||
# def delete
|
||||
|
||||
# def trace
|
||||
|
||||
# def options
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
def do_quit
|
||||
unless @socket.closed? then
|
||||
@socket.close
|
||||
end
|
||||
end
|
||||
|
||||
def get_response( line, u_header )
|
||||
@socket.writeline line
|
||||
write_header u_header
|
||||
rep = get_reply
|
||||
header = read_header
|
||||
reply_must rep, SuccessCode
|
||||
|
||||
header
|
||||
end
|
||||
|
||||
def get_reply
|
||||
str = @socket.readline
|
||||
unless /\AHTTP\/(\d+\.\d+)?\s+(\d\d\d)\s*(.*)\z/i === str then
|
||||
raise HTTPBadResponse, "wrong status line format: #{str}"
|
||||
end
|
||||
@http_version = $1
|
||||
status = $2
|
||||
discrip = $3
|
||||
|
||||
klass = case status[0]
|
||||
when ?1 then
|
||||
case status[2]
|
||||
when ?0 then ContinueCode
|
||||
when ?1 then SuccessCode
|
||||
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 )
|
||||
end
|
||||
|
||||
|
||||
def content_length( header )
|
||||
unless str = header[ 'content-length' ] then
|
||||
raise HTTPBadResponce, "content-length not given"
|
||||
end
|
||||
unless /\Acontent-length:\s*(\d+)/i === str then
|
||||
raise HTTPBadResponce, "content-length format error"
|
||||
end
|
||||
$1.to_i
|
||||
end
|
||||
|
||||
def keep_alive?( header )
|
||||
if str = header[ 'connection' ] then
|
||||
if /\Aconnection:\s*keep-alive/i === str then
|
||||
return true
|
||||
end
|
||||
else
|
||||
if @http_version == '1.1' then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def chunked?( header )
|
||||
if str = header[ 'transfer-encoding' ] then
|
||||
if /\Atransfer-encoding:\s*chunked/i === str then
|
||||
return true
|
||||
end
|
||||
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 HTTPBadResponce, "chunk size not given"
|
||||
|
||||
def do_finish
|
||||
unless @command.error_occured or @socket.closed? then
|
||||
head '/', { 'Connection' => 'Close' }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def edit_path( path )
|
||||
path
|
||||
end
|
||||
|
||||
class << self
|
||||
def Proxy( p_addr, p_port )
|
||||
klass = super
|
||||
klass.module_eval %-
|
||||
def edit_path( path )
|
||||
'http://' + address +
|
||||
(@port == #{self.port} ? '' : ':' + @port.to_s) + path
|
||||
end
|
||||
-
|
||||
klass
|
||||
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
|
||||
HTTPSession = HTTP
|
||||
|
||||
|
||||
class HTTPCommand < Command
|
||||
|
||||
HTTPVersion = '1.1'
|
||||
|
||||
def initialize( sock )
|
||||
@http_version = HTTPVersion
|
||||
|
||||
@in_header = {}
|
||||
@in_header[ 'Host' ] = sock.addr
|
||||
@in_header[ 'Connection' ] = 'keep-alive'
|
||||
@in_header[ 'Accept' ] = '*/*'
|
||||
|
||||
super sock
|
||||
end
|
||||
|
||||
|
||||
attr :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
|
||||
@socket.read content_length( header ), ret
|
||||
end
|
||||
|
||||
header
|
||||
end
|
||||
|
||||
|
||||
def head( path, u_header = nil )
|
||||
get_response sprintf( 'HEAD %s HTTP/%s', path, HTTPVersion ), u_header
|
||||
end
|
||||
|
||||
|
||||
# def put
|
||||
|
||||
# def delete
|
||||
|
||||
# def trace
|
||||
|
||||
# def options
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
def do_quit
|
||||
unless @socket.closed? then
|
||||
@socket.close
|
||||
end
|
||||
end
|
||||
|
||||
def get_response( line, u_header )
|
||||
@socket.writeline line
|
||||
write_header u_header
|
||||
rep = get_reply
|
||||
header = read_header
|
||||
reply_must rep, SuccessCode
|
||||
|
||||
header
|
||||
end
|
||||
|
||||
def get_reply
|
||||
str = @socket.readline
|
||||
unless /\AHTTP\/(\d+\.\d+)?\s+(\d\d\d)\s*(.*)\z/i === str then
|
||||
raise HTTPBadResponse, "wrong status line format: #{str}"
|
||||
end
|
||||
@http_version = $1
|
||||
status = $2
|
||||
discrip = $3
|
||||
|
||||
klass = case status[0]
|
||||
when ?1 then
|
||||
case status[2]
|
||||
when ?0 then ContinueCode
|
||||
when ?1 then SuccessCode
|
||||
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 )
|
||||
end
|
||||
|
||||
|
||||
def content_length( header )
|
||||
unless str = header[ 'content-length' ] then
|
||||
raise HTTPBadResponce, "content-length not given"
|
||||
end
|
||||
unless /\Acontent-length:\s*(\d+)/i === str then
|
||||
raise HTTPBadResponce, "content-length format error"
|
||||
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
|
||||
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 HTTPBadResponce, "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 # module Net
|
||||
|
|
106
lib/net/pop.rb
106
lib/net/pop.rb
|
@ -4,8 +4,8 @@
|
|||
|
||||
written by Minero Aoki <aamine@dp.u-netsurf.ne.jp>
|
||||
|
||||
This library is distributed under the terms of Ruby license.
|
||||
You can freely distribute/modify this file.
|
||||
This library is distributed under the terms of the Ruby license.
|
||||
You can freely distribute/modify this library.
|
||||
|
||||
=end
|
||||
|
||||
|
@ -19,17 +19,17 @@ module Net
|
|||
|
||||
=begin
|
||||
|
||||
== Net::POP3Session
|
||||
== Net::POP3
|
||||
|
||||
=== Super Class
|
||||
|
||||
Net::Session
|
||||
Net::Protocol
|
||||
|
||||
=== Class Methods
|
||||
|
||||
: new( address = 'localhost', port = 110 )
|
||||
|
||||
This method create a new POP3Session object.
|
||||
This method create a new POP3 object.
|
||||
This will not open connection yet.
|
||||
|
||||
|
||||
|
@ -37,11 +37,11 @@ Net::Session
|
|||
|
||||
: start( account, password )
|
||||
|
||||
This method start POP session.
|
||||
This method start POP3.
|
||||
|
||||
: each{|popmail| ...}
|
||||
|
||||
This method is equals to "pop3session.mails.each"
|
||||
This method is equals to "pop3.mails.each"
|
||||
|
||||
: mails
|
||||
|
||||
|
@ -50,12 +50,19 @@ Net::Session
|
|||
|
||||
=end
|
||||
|
||||
class POP3Session < Session
|
||||
class POP3 < Protocol
|
||||
|
||||
Version = '1.1.2'
|
||||
Version = '1.1.3'
|
||||
|
||||
session_setvar :port, '110'
|
||||
session_setvar :command_type, 'Net::POP3Command'
|
||||
protocol_param :port, '110'
|
||||
protocol_param :command_type, '::Net::POP3Command'
|
||||
|
||||
protocol_param :mail_type, '::Net::POPMail'
|
||||
|
||||
def initialize( addr = nil, port = nil )
|
||||
super
|
||||
@mails = [].freeze
|
||||
end
|
||||
|
||||
|
||||
attr :mails
|
||||
|
@ -68,25 +75,23 @@ Net::Session
|
|||
private
|
||||
|
||||
|
||||
def proto_initialize
|
||||
@mails = [].freeze
|
||||
end
|
||||
|
||||
def do_start( acnt, pwd )
|
||||
@proto.auth( acnt, pwd )
|
||||
@command.auth( acnt, pwd )
|
||||
t = self.type.mail_type
|
||||
@mails = []
|
||||
@proto.list.each_with_index do |size,idx|
|
||||
@command.list.each_with_index do |size,idx|
|
||||
if size then
|
||||
@mails.push POPMail.new( idx, size, @proto )
|
||||
@mails.push t.new( idx, size, @command )
|
||||
end
|
||||
end
|
||||
@mails.freeze
|
||||
end
|
||||
|
||||
end # POP3Session
|
||||
end
|
||||
|
||||
POPSession = POP3Session
|
||||
POP3 = POP3Session
|
||||
POP = POP3
|
||||
POPSession = POP3
|
||||
POP3Session = POP3
|
||||
|
||||
|
||||
=begin
|
||||
|
@ -133,10 +138,10 @@ Object
|
|||
|
||||
class POPMail
|
||||
|
||||
def initialize( idx, siz, pro )
|
||||
@num = idx
|
||||
@size = siz
|
||||
@proto = pro
|
||||
def initialize( n, s, cmd )
|
||||
@num = n
|
||||
@size = s
|
||||
@command = cmd
|
||||
|
||||
@deleted = false
|
||||
end
|
||||
|
@ -145,13 +150,13 @@ Object
|
|||
attr :size
|
||||
|
||||
def all( dest = '' )
|
||||
@proto.retr( @num, dest )
|
||||
@command.retr( @num, dest )
|
||||
end
|
||||
alias pop all
|
||||
alias mail all
|
||||
|
||||
def top( lines, dest = '' )
|
||||
@proto.top( @num, lines, dest )
|
||||
@command.top( @num, lines, dest )
|
||||
end
|
||||
|
||||
def header( dest = '' )
|
||||
|
@ -159,7 +164,7 @@ Object
|
|||
end
|
||||
|
||||
def delete
|
||||
@proto.dele( @num )
|
||||
@command.dele( @num )
|
||||
@deleted = true
|
||||
end
|
||||
alias delete! delete
|
||||
|
@ -169,7 +174,7 @@ Object
|
|||
end
|
||||
|
||||
def uidl
|
||||
@proto.uidl @num
|
||||
@command.uidl @num
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -177,30 +182,30 @@ Object
|
|||
|
||||
=begin
|
||||
|
||||
== Net::APOP3Session
|
||||
== Net::APOP
|
||||
|
||||
This class has no new methods. Only way of authetication is changed.
|
||||
|
||||
=== Super Class
|
||||
|
||||
Net::POP3Session
|
||||
Net::POP3
|
||||
|
||||
=end
|
||||
|
||||
class APOPSession < POP3Session
|
||||
class APOP < POP3
|
||||
|
||||
session_setvar :command_type, 'Net::APOPCommand'
|
||||
protocol_param :command_type, 'Net::APOPCommand'
|
||||
|
||||
end
|
||||
|
||||
APOP = APOPSession
|
||||
APOPSession = APOP
|
||||
|
||||
|
||||
=begin
|
||||
|
||||
== Net::POP3Command
|
||||
|
||||
POP3 protocol class.
|
||||
POP3 command class.
|
||||
|
||||
=== Super Class
|
||||
|
||||
|
@ -240,7 +245,7 @@ Net::Command
|
|||
|
||||
: quit
|
||||
|
||||
This method finishes POP3 session.
|
||||
This method ends POP using 'QUIT' commmand.
|
||||
|
||||
: rset
|
||||
|
||||
|
@ -276,7 +281,7 @@ Net::Command
|
|||
|
||||
|
||||
def auth( acnt, pass )
|
||||
@socket.writeline( 'USER ' + acnt )
|
||||
@socket.writeline 'USER ' + acnt
|
||||
check_reply_auth
|
||||
|
||||
@socket.writeline( 'PASS ' + pass )
|
||||
|
@ -287,8 +292,7 @@ Net::Command
|
|||
|
||||
|
||||
def list
|
||||
@socket.writeline( 'LIST' )
|
||||
check_reply( SuccessCode )
|
||||
getok 'LIST'
|
||||
|
||||
arr = []
|
||||
@socket.read_pendlist do |line|
|
||||
|
@ -301,36 +305,29 @@ Net::Command
|
|||
|
||||
|
||||
def rset
|
||||
@socket.writeline( 'RSET' )
|
||||
check_reply( SuccessCode )
|
||||
getok 'RSET'
|
||||
end
|
||||
|
||||
|
||||
def top( num, lines = 0, dest = '' )
|
||||
@socket.writeline( sprintf( 'TOP %d %d', num, lines ) )
|
||||
check_reply( SuccessCode )
|
||||
|
||||
return @socket.read_pendstr( dest )
|
||||
getok sprintf( 'TOP %d %d', num, lines )
|
||||
@socket.read_pendstr( dest )
|
||||
end
|
||||
|
||||
|
||||
def retr( num, dest = '', &block )
|
||||
@socket.writeline( sprintf( 'RETR %d', num ) )
|
||||
check_reply( SuccessCode )
|
||||
|
||||
return @socket.read_pendstr( dest, &block )
|
||||
getok sprintf( 'RETR %d', num )
|
||||
@socket.read_pendstr( dest, &block )
|
||||
end
|
||||
|
||||
|
||||
def dele( num )
|
||||
@socket.writeline( 'DELE ' + num.to_s )
|
||||
check_reply( SuccessCode )
|
||||
getok sprintf( 'DELE %d', num )
|
||||
end
|
||||
|
||||
|
||||
def uidl( num )
|
||||
@socket.writeline( 'UIDL ' + num.to_s )
|
||||
rep = check_reply( SuccessCode )
|
||||
rep = getok( sprintf 'UIDL %d', num )
|
||||
uid = rep.msg.split(' ')[1]
|
||||
|
||||
uid
|
||||
|
@ -341,8 +338,7 @@ Net::Command
|
|||
|
||||
|
||||
def do_quit
|
||||
@socket.writeline( 'QUIT' )
|
||||
check_reply( SuccessCode )
|
||||
getok 'QUIT'
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
=begin
|
||||
|
||||
= net/session.rb version 1.1.2
|
||||
= net/session.rb version 1.1.3
|
||||
|
||||
written by Minero Aoki <aamine@dp.u-netsurf.ne.jp>
|
||||
|
||||
This library is distributed under the terms of Ruby style license.
|
||||
You can freely distribute/modify this file.
|
||||
This library is distributed under the terms of the Ruby license.
|
||||
You can freely distribute/modify this library.
|
||||
|
||||
=end
|
||||
|
||||
|
@ -18,9 +18,9 @@ module Net
|
|||
|
||||
=begin
|
||||
|
||||
== Net::Session
|
||||
== Net::Protocol
|
||||
|
||||
the abstruct class for Internet protocol session
|
||||
the abstruct class for Internet protocol
|
||||
|
||||
=== Super Class
|
||||
|
||||
|
@ -30,22 +30,27 @@ Object
|
|||
|
||||
: Version
|
||||
|
||||
The version of Session class. It is a string like "1.1.2".
|
||||
The version of Session class. It is a string like "1.1.3".
|
||||
|
||||
|
||||
=== Class Methods
|
||||
|
||||
: new( address = 'localhost', port = nil )
|
||||
|
||||
This method Create a new Session object.
|
||||
This method Creates a new Session object.
|
||||
|
||||
: start( address = 'localhost', port = nil, *args )
|
||||
: start( address = 'localhost', port = nil, *args ){|session| .... }
|
||||
|
||||
This method create a new Session object and start session.
|
||||
This method creates a new Session object and start session.
|
||||
If you call this method with block, Session object give itself
|
||||
to block and finish session when block returns.
|
||||
|
||||
: Proxy( address, port )
|
||||
|
||||
This method creates a proxy class of its protocol.
|
||||
Arguments are address/port of proxy host.
|
||||
|
||||
|
||||
=== Methods
|
||||
|
||||
|
@ -59,14 +64,14 @@ Object
|
|||
|
||||
: start( *args )
|
||||
|
||||
This method start session. If you call this method when the session
|
||||
This method start protocol. If you call this method when the protocol
|
||||
is already started, this only returns false without doing anything.
|
||||
|
||||
'*args' are specified in subclasses.
|
||||
|
||||
: finish
|
||||
|
||||
This method finish session. If you call this method before session starts,
|
||||
This method ends protocol. If you call this method before protocol starts,
|
||||
it only return false without doing anything.
|
||||
|
||||
: active?
|
||||
|
@ -75,20 +80,20 @@ Object
|
|||
|
||||
=end
|
||||
|
||||
class Session
|
||||
class Protocol
|
||||
|
||||
Version = '1.1.2'
|
||||
Version = '1.1.3'
|
||||
|
||||
class << self
|
||||
|
||||
def start( address = 'localhost', port = nil, *args )
|
||||
session = new( address, port )
|
||||
instance = new( address, port )
|
||||
|
||||
if iterator? then
|
||||
session.start( *args ) { yield session }
|
||||
instance.start( *args ) { yield instance }
|
||||
else
|
||||
session.start *args
|
||||
session
|
||||
instance.start *args
|
||||
instance
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -104,11 +109,8 @@ Object
|
|||
@port = port
|
||||
end
|
||||
|
||||
def connect
|
||||
tmpa, tmpp = @address, @port
|
||||
@address, @port = @proxyaddr, @proxyport
|
||||
super
|
||||
@address, @port = tmpa, tmpp
|
||||
def connect( addr, port )
|
||||
super @proxyaddr, @proxyport
|
||||
end
|
||||
private :connect
|
||||
|
||||
|
@ -129,7 +131,7 @@ Object
|
|||
|
||||
private
|
||||
|
||||
def session_setvar( name, val )
|
||||
def protocol_param( name, val )
|
||||
module_eval %-
|
||||
def self.#{name.id2name}
|
||||
#{val}
|
||||
|
@ -143,26 +145,26 @@ Object
|
|||
#
|
||||
# sub-class requirements
|
||||
#
|
||||
# session_setvar command_type
|
||||
# session_setvar port
|
||||
# protocol_param command_type
|
||||
# protocol_param port
|
||||
#
|
||||
# private method do_start (optional)
|
||||
# private method do_finish (optional)
|
||||
#
|
||||
|
||||
session_setvar :port, 'nil'
|
||||
session_setvar :command_type, 'nil'
|
||||
session_setvar :socket_type, 'Net::ProtocolSocket'
|
||||
protocol_param :port, 'nil'
|
||||
protocol_param :command_type, 'nil'
|
||||
protocol_param :socket_type, '::Net::ProtocolSocket'
|
||||
|
||||
|
||||
def initialize( addr = 'localhost', port = nil )
|
||||
@address = addr
|
||||
def initialize( addr = nil, port = nil )
|
||||
@address = addr || 'localhost'
|
||||
@port = port || self.type.port
|
||||
|
||||
@active = false
|
||||
@pipe = nil
|
||||
|
||||
@proto = nil
|
||||
@command = nil
|
||||
@socket = nil
|
||||
end
|
||||
|
||||
|
@ -170,6 +172,7 @@ Object
|
|||
attr :address
|
||||
attr :port
|
||||
|
||||
attr :command
|
||||
attr :socket
|
||||
|
||||
|
||||
|
@ -178,7 +181,7 @@ Object
|
|||
@active = true
|
||||
|
||||
begin
|
||||
connect
|
||||
connect @address, @port
|
||||
do_start *args
|
||||
yield if iterator?
|
||||
ensure
|
||||
|
@ -187,7 +190,7 @@ Object
|
|||
end
|
||||
|
||||
def finish
|
||||
if @proto then
|
||||
if @command then
|
||||
do_finish
|
||||
disconnect
|
||||
end
|
||||
|
@ -225,19 +228,21 @@ Object
|
|||
end
|
||||
|
||||
|
||||
def connect
|
||||
@socket = self.type.socket_type.open( @address, @port, @pipe )
|
||||
@proto = self.type.command_type.new( @socket )
|
||||
def connect( addr, port )
|
||||
@socket = self.type.socket_type.open( addr, port, @pipe )
|
||||
@command = self.type.command_type.new( @socket )
|
||||
end
|
||||
|
||||
def disconnect
|
||||
@proto.quit
|
||||
@proto = nil
|
||||
@socket = nil
|
||||
@command.quit
|
||||
@command = nil
|
||||
@socket = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Session = Protocol
|
||||
|
||||
|
||||
=begin
|
||||
|
||||
|
@ -259,7 +264,7 @@ Object
|
|||
|
||||
: quit
|
||||
|
||||
This method finishes protocol.
|
||||
This method dispatch command which ends the protocol.
|
||||
|
||||
=end
|
||||
|
||||
|
@ -301,6 +306,11 @@ Object
|
|||
@error_occured = true
|
||||
rep.error! @socket.sending
|
||||
end
|
||||
|
||||
def getok( line, ok = SuccessCode )
|
||||
@socket.writeline line
|
||||
check_reply ok
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
written by Minero Aoki <aamine@dp.u-netsurf.ne.jp>
|
||||
|
||||
This library is distributed under the terms of Ruby license.
|
||||
You can freely distribute/modify this file.
|
||||
This library is distributed under the terms of the Ruby license.
|
||||
You can freely distribute/modify this library.
|
||||
|
||||
=end
|
||||
|
||||
|
@ -18,57 +18,57 @@ module Net
|
|||
|
||||
=begin
|
||||
|
||||
== Net::SMTPSession
|
||||
== Net::SMTP
|
||||
|
||||
=== Super Class
|
||||
|
||||
Net::Session
|
||||
Net::Protocol
|
||||
|
||||
=== Class Methods
|
||||
|
||||
: new( address = 'localhost', port = 25 )
|
||||
|
||||
This method create new SMTPSession object.
|
||||
This method create new SMTP object.
|
||||
|
||||
|
||||
=== Methods
|
||||
|
||||
: start( helo_domain = ENV['HOSTNAME'] )
|
||||
|
||||
This method opens TCP connection and start SMTP session.
|
||||
If session had been started, do nothing and return false.
|
||||
This method opens TCP connection and start SMTP.
|
||||
If protocol had been started, do nothing and return false.
|
||||
|
||||
: sendmail( mailsrc, from_domain, to_addrs )
|
||||
|
||||
This method sends 'mailsrc' as mail. SMTPSession read strings from 'mailsrc'
|
||||
by calling 'each' iterator, and convert them into "\r\n" terminated string when write.
|
||||
|
||||
SMTPSession's Exceptions are:
|
||||
* Protocol::ProtoSyntaxError: syntax error (errno.500)
|
||||
* Protocol::ProtoFatalError: fatal error (errno.550)
|
||||
* Protocol::ProtoUnknownError: unknown error
|
||||
* Protocol::ProtoServerBusy: temporary error (errno.420/450)
|
||||
Exceptions which SMTP raises are:
|
||||
* Net::ProtoSyntaxError: syntax error (errno.500)
|
||||
* Net::ProtoFatalError: fatal error (errno.550)
|
||||
* Net::ProtoUnknownError: unknown error
|
||||
* Net::ProtoServerBusy: temporary error (errno.420/450)
|
||||
|
||||
: finish
|
||||
|
||||
This method closes SMTP session.
|
||||
If session had not started, do nothind and return false.
|
||||
This method ends SMTP.
|
||||
If protocol had not started, do nothind and return false.
|
||||
|
||||
=end
|
||||
|
||||
class SMTPSession < Session
|
||||
class SMTP < Protocol
|
||||
|
||||
Version = '1.1.2'
|
||||
Version = '1.1.3'
|
||||
|
||||
session_setvar :port, '25'
|
||||
session_setvar :command_type, 'Net::SMTPCommand'
|
||||
protocol_param :port, '25'
|
||||
protocol_param :command_type, '::Net::SMTPCommand'
|
||||
|
||||
|
||||
def sendmail( mailsrc, fromaddr, toaddrs )
|
||||
@proto.mailfrom fromaddr
|
||||
@proto.rcpt toaddrs
|
||||
@proto.data
|
||||
@proto.sendmail mailsrc
|
||||
@command.mailfrom fromaddr
|
||||
@command.rcpt toaddrs
|
||||
@command.data
|
||||
@command.sendmail mailsrc
|
||||
end
|
||||
|
||||
|
||||
|
@ -79,12 +79,12 @@ Net::Session
|
|||
unless helodom then
|
||||
raise ArgumentError, "cannot get hostname"
|
||||
end
|
||||
@proto.helo helodom
|
||||
@command.helo helodom
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
SMTP = SMTPSession
|
||||
SMTPSession = SMTP
|
||||
|
||||
|
||||
=begin
|
||||
|
@ -99,14 +99,14 @@ Net::Command
|
|||
|
||||
: new( socket )
|
||||
|
||||
This method creates new SMTPCommand object, and open SMTP session.
|
||||
This method creates new SMTPCommand object, and open SMTP.
|
||||
|
||||
|
||||
=== Methods
|
||||
|
||||
: helo( helo_domain )
|
||||
|
||||
This method send "HELO" command and start SMTP session.
|
||||
This method send "HELO" command and start SMTP.
|
||||
helo_domain is localhost's FQDN.
|
||||
|
||||
: mailfrom( from_addr )
|
||||
|
@ -139,34 +139,30 @@ Net::Command
|
|||
|
||||
|
||||
def helo( fromdom )
|
||||
@socket.writeline( 'HELO ' << fromdom )
|
||||
check_reply( SuccessCode )
|
||||
getok sprintf( 'HELO %s', fromdom )
|
||||
end
|
||||
|
||||
|
||||
def mailfrom( fromaddr )
|
||||
@socket.writeline( 'MAIL FROM:<' + fromaddr + '>' )
|
||||
check_reply( SuccessCode )
|
||||
getok sprintf( 'MAIL FROM:<%s>', fromaddr )
|
||||
end
|
||||
|
||||
|
||||
def rcpt( toaddrs )
|
||||
toaddrs.each do |i|
|
||||
@socket.writeline( 'RCPT TO:<' + i + '>' )
|
||||
check_reply( SuccessCode )
|
||||
getok sprintf( 'RCPT TO:<%s>', i )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def data
|
||||
@socket.writeline( 'DATA' )
|
||||
check_reply( ContinueCode )
|
||||
getok 'DATA', ContinueCode
|
||||
end
|
||||
|
||||
|
||||
def writemail( mailsrc )
|
||||
@socket.write_pendstr( mailsrc )
|
||||
check_reply( SuccessCode )
|
||||
@socket.write_pendstr mailsrc
|
||||
check_reply SuccessCode
|
||||
end
|
||||
alias sendmail writemail
|
||||
|
||||
|
@ -175,8 +171,7 @@ Net::Command
|
|||
|
||||
|
||||
def do_quit
|
||||
@socket.writeline( 'QUIT' )
|
||||
check_reply( SuccessCode )
|
||||
getok 'QUIT'
|
||||
end
|
||||
|
||||
|
||||
|
@ -184,19 +179,19 @@ Net::Command
|
|||
arr = read_reply
|
||||
stat = arr[0][0,3]
|
||||
|
||||
cls = UnknownCode
|
||||
case stat[0]
|
||||
when ?2 then cls = SuccessCode
|
||||
when ?3 then cls = ContinueCode
|
||||
when ?4 then cls = ServerBusyCode
|
||||
when ?5 then
|
||||
case stat[1]
|
||||
when ?0 then cls = SyntaxErrorCode
|
||||
when ?5 then cls = FatalErrorCode
|
||||
end
|
||||
end
|
||||
klass = UnknownCode
|
||||
klass = case stat[0]
|
||||
when ?2 then SuccessCode
|
||||
when ?3 then ContinueCode
|
||||
when ?4 then ServerBusyCode
|
||||
when ?5 then
|
||||
case stat[1]
|
||||
when ?0 then SyntaxErrorCode
|
||||
when ?5 then FatalErrorCode
|
||||
end
|
||||
end
|
||||
|
||||
return cls.new( stat, arr.join('') )
|
||||
klass.new( stat, arr.join('') )
|
||||
end
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue