o  http.rb
o  support class swap
o  Net.quote


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@588 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
aamine 1999-12-17 15:00:13 +00:00
Родитель 9d228b13de
Коммит 6f4751f5f6
4 изменённых файлов: 617 добавлений и 382 удалений

200
lib/net/http.rb Normal file
Просмотреть файл

@ -0,0 +1,200 @@
=begin
= net/http.rb
maintained by Minero Aoki <aamine@dp.u-netsurf.ne.jp>
This file is derived from http-access.rb
=end
require 'net/session'
module Net
class HTTPError < ProtocolError; end
class HTTPBadResponse < HTTPError; end
class HTTPSession < Session
Version = '1.1.0'
session_setvar :port, '80'
session_setvar :command_type, 'HTTPCommand'
def get( path = '/', header = nil, ret = '' )
confirm_connection
@proto.get path, header, ret
end
def head( path = '/', header = nil )
confirm_connection
@proto.head path, header
end
private
def confirm_connection
if @socket.closed? then
@socket.reopen
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 = '' )
@socket.writeline sprintf( 'GET %s HTTP/%s', path, HTTPVersion )
write_header u_header
check_reply SuccessCode
header = read_header
@socket.read content_length( header ), ret
@socket.close unless keep_alive? header
return header, ret
end
def head( path, u_header = nil )
@socket.writeline sprintf( 'HEAD %s HTTP/%s', path, HTTPVersion )
write_header u_header
check_reply SuccessCode
header = read_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
head '/', { 'Connection' => 'Close' }
end
end
def get_reply
str = @socket.readline
/\AHTTP\/(\d+\.\d+)?\s+(\d\d\d)\s+(.*)\z/i === str
@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 /content-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 /connection:\s*keep-alive/i === str then
return true
end
else
if @http_version == '1.1' 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
end
end # module Net

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

@ -1,11 +1,11 @@
=begin
= Net module version 1.0.3 reference manual
= net/pop.rb
pop.rb written by Minero Aoki <aamine@dp.u-netsurf.ne.jp>
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/copy this file.
This library is distributed under the terms of Ruby license.
You can freely distribute/modify this file.
=end
@ -16,6 +16,7 @@ require 'md5'
module Net
=begin
== Net::POP3Session
@ -28,14 +29,9 @@ Net::Session
: new( address = 'localhost', port = 110 )
This method create a new POP3Session object but this will not open connection.
This method create a new POP3Session object.
This will not open connection yet.
=end
class POP3Session < Session
=begin
=== Methods
@ -45,30 +41,35 @@ Net::Session
: each{|popmail| ...}
This method is equals to "POP3Session.mails.each"
This method is equals to "pop3session.mails.each"
: mails
This method returns an array of <a href="#popi">POP3Session::POPMail</a>.
This method returns an array of ((URL:#POPMail)).
This array is renewed when login.
=end
class POP3Session < Session
session_setvar :port, '110'
session_setvar :command_type, 'POP3Command'
attr :mails
def each() @mails.each{|m| yield m} end
def each
@mails.each {|m| yield m }
end
private
def proto_initialize
@proto_type = POP3Command
@port = 110
@mails = [].freeze
end
def do_start( acnt, pwd )
@proto.auth( acnt, pwd )
@mails = []
@ -80,15 +81,15 @@ Net::Session
@mails.freeze
end
end # POP3Session
def do_finish
@proto.quit
end
POPSession = POP3Session
POP3 = POP3Session
=begin
== Net::POP3Session::POPMail
== Net::POPMail
A class of mail which exists on POP server.
@ -96,19 +97,6 @@ A class of mail which exists on POP server.
Object
=end
class POPMail
def initialize( idx, siz, pro )
@num = idx
@size = siz
@proto = pro
@deleted = false
end
=begin
=== Method
@ -141,42 +129,48 @@ Object
=end
attr :size
class POPMail
def all( dest = '' )
@proto.retr( @num, dest )
end
alias pop all
alias mail all
def top( lines, dest = '' )
@proto.top( @num, lines, dest )
end
def header( dest = '' )
top( 0, dest )
end
def delete
@proto.dele( @num )
@deleted = true
end
alias delete! delete
def deleted?
@deleted
end
def uidl
@proto.uidl @num
end
def initialize( idx, siz, pro )
@num = idx
@size = siz
@proto = pro
@deleted = false
end
end # POP3Session
POPSession = POP3Session
POP3 = POP3Session
attr :size
def all( dest = '' )
@proto.retr( @num, dest )
end
alias pop all
alias mail all
def top( lines, dest = '' )
@proto.top( @num, lines, dest )
end
def header( dest = '' )
top( 0, dest )
end
def delete
@proto.dele( @num )
@deleted = true
end
alias delete! delete
def deleted?
@deleted
end
def uidl
@proto.uidl @num
end
end
=begin
@ -193,10 +187,7 @@ Net::POP3Session
class APOPSession < POP3Session
def proto_initialize
super
@proto_type = APOPCommand
end
session_setvar :command_type, 'APOPCommand'
end
@ -219,17 +210,6 @@ Net::Command
This method creates new POP3Command object. 'socket' must be ProtocolSocket.
=end
class POP3Command < Command
def initialize( sock )
@uidl = nil
super
end
=begin
=== Methods
@ -284,6 +264,15 @@ Net::Command
=end
class POP3Command < Command
def initialize( sock )
super
check_reply SuccessCode
end
def auth( acnt, pass )
@socket.writeline( 'USER ' + acnt )
check_reply_auth
@ -385,7 +374,7 @@ Net::Command
=== Super Class
POP3
POP3Command
=== Methods
@ -428,9 +417,4 @@ POP3
end
unless Session::Version == '1.0.3' then
$stderr.puts "WARNING: wrong version of session.rb & pop.rb"
end
end

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

@ -1,11 +1,11 @@
=begin
= Net module version 1.0.3 reference manual
= net/session.rb version 1.1.0
session.rb written by Minero Aoki <aamine@dp.u-netsurf.ne.jp>
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/copy this file.
You can freely distribute/modify this file.
=end
@ -13,16 +13,7 @@ You can freely distribute/modify/copy this file.
require 'socket'
class String
def doquote
str = self.gsub( "\n", '\\n' )
str.gsub!( "\r", '\\r' )
str.gsub!( "\t", '\\t' )
return str
end
end
module Net
=begin
@ -39,18 +30,8 @@ Object
: Version
The version of Session class. It is a string like "1.0.3".
The version of Session class. It is a string like "1.1.0".
=end
module Net
class Session
Version = '1.0.3'
=begin
=== Class Methods
@ -65,31 +46,6 @@ module Net
If you call this method with block, Session object give itself
to block and finish session when block returns.
=end
def initialize( addr = 'localhost', port = nil )
proto_initialize
@address = addr
@port = port if port
@active = false
@pipe = nil
end
class << self
def start( address = 'localhost', port = nil, *args )
inst = new( address, port )
ret = inst.start( *args )
if iterator? then
ret = yield( inst )
inst.finish
end
return ret
end
end
=begin
=== Methods
@ -101,18 +57,6 @@ module Net
connecting port number
=end
attr :address
attr :port
attr :socket
attr :proto_type
attr :proto, true
=begin
: start( *args )
This method start session. If you call this method when the session
@ -131,28 +75,96 @@ module Net
=end
class Session
Version = '1.1.0'
class << self
def start( address = 'localhost', port = nil, *args )
session = new( address, port )
if iterator? then
session.start( *args ) { yield session }
else
session.start *args
session
end
end
private
def session_setvar( name, val )
module_eval %-
def self.#{name.id2name}
#{val}
end
-
end
end
#
# sub-class requirements
#
# class method command_type
# class method port
#
# private method proto_initialize
# private method do_start (optional)
# private method do_finish (optional)
#
session_setvar :port, 'nil'
session_setvar :command_type, 'nil'
session_setvar :socket_type, 'ProtocolSocket'
def initialize( addr = 'localhost', port = nil )
@address = addr
@port = port || self.type.port
@active = false
@pipe = nil
@proto = nil
@socket = nil
end
attr :address
attr :port
attr :socket
def start( *args )
return false if active?
@active = true
if Class === args[0] then
c = args.shift
else
c = ProtocolSocket
begin
connect
do_start *args
yield if iterator?
ensure
finish if iterator?
end
@socket = c.open( @address, @port, @pipe )
@pipe = nil
@proto = @proto_type.new( @socket )
do_start( *args )
end
def finish
@active = false
if @proto then
do_finish
@proto = nil
disconnect
end
if @socket and not @socket.closed? then
@socket.close
@socket = nil
end
if active? then
@active = false
return true
else
@ -160,12 +172,36 @@ module Net
end
end
def active?() @active end
def active?
@active
end
def set_pipe( arg )
def set_pipe( arg ) # un-documented
@pipe = arg
end
private
def do_start
end
def do_finish
end
def connect
@socket = self.type.socket_type.open( @address, @port, @pipe )
@proto = self.type.command_type.new( @socket )
end
def disconnect
@proto.quit
@proto = nil
@socket = nil
end
end
@ -197,7 +233,6 @@ Object
def initialize( sock )
@socket = sock
check_reply( SuccessCode )
end
attr :socket, true
@ -248,39 +283,47 @@ Object
attr :msg
def error!( sending )
err, tag = Errors[ self.type ]
mes = sprintf( <<MES, tag, @code, sending.doquote, @msg.doquote )
mes = <<MES
%s: status %s
status %s
writing string is:
%s
error message from server is:
%s
MES
raise err, mes
raise self.type::Error,
sprintf( mes, @code, Net.quote(sending), Net.quote(@msg) )
end
end
class SuccessCode < ReplyCode ; end
class ContinueCode < SuccessCode ; end
class ErrorCode < ReplyCode ; end
class SyntaxErrorCode < ErrorCode ; end
class FatalErrorCode < ErrorCode ; end
class ServerBusyCode < ErrorCode ; end
class UnknownCode < ReplyCode ; end
class SuccessCode < ReplyCode
Error = ProtoUnknownError
end
class ReplyCode
Errors = {
SuccessCode => [ ProtoUnknownError, 'unknown error' ],
ContinueCode => [ ProtoUnknownError, 'unknown error' ],
ErrorCode => [ ProtocolError, 'protocol error' ],
SyntaxErrorCode => [ ProtoSyntaxError, 'syntax error' ],
FatalErrorCode => [ ProtoFatalError, 'fatal error' ],
ServerBusyCode => [ ProtoServerError, 'probably server busy' ],
UnknownCode => [ ProtoUnknownError, 'unknown error' ]
}
class ContinueCode < SuccessCode
Error = ProtoUnknownError
end
class ErrorCode < ReplyCode
Error = ProtocolError
end
class SyntaxErrorCode < ErrorCode
Error = ProtoSyntaxError
end
class FatalErrorCode < ErrorCode
Error = ProtoFatalError
end
class ServerBusyCode < ErrorCode
Error = ProtoServerError
end
class UnknownCode < ReplyCode
Error = ProtoUnknownError
end
@ -298,31 +341,6 @@ Object
This create new ProtocolSocket object, and connect to server.
=end
class ProtocolSocket
def initialize( addr, port, pipe = nil )
@address = addr
@port = port
@pipe = pipe
@ipaddr = ''
@closed = false
@sending = ''
@buffer = ''
@socket = TCPsocket.new( addr, port )
@ipaddr = @socket.addr[3]
end
attr :pipe, true
class << self
alias open new
end
=begin
=== Methods
@ -330,11 +348,11 @@ Object
This method closes socket.
: addr
: address, addr
a FQDN address of server
: ipaddr
: ip_address, ipaddr
an IP address of server
@ -346,30 +364,6 @@ Object
true if ProtocolSokcet have been closed already
=end
attr :socket, true
def close
@socket.close
@closed = true
end
def closed?() @closed end
def addr() @address.dup end
def port() @port end
def ipaddr() @ipaddr.dup end
attr :sending
CRLF = "\r\n"
D_CRLF = ".\r\n"
TERMEXP = /\n|\r\n|\r/o
=begin
: read( length )
@ -397,92 +391,6 @@ Object
When this method was called with block, evaluate it for each reading a line.
=end
def read( len, ret = '' )
rsize = 0
while rsize + @buffer.size < len do
rsize += @buffer.size
ret << fetch_rbuf( @buffer.size )
fill_rbuf
end
ret << fetch_rbuf( len - rsize )
return ret
end
def readuntil( target )
until idx = @buffer.index( target ) do
fill_rbuf
end
return fetch_rbuf( idx + target.size )
end
def readline
ret = readuntil( CRLF )
ret.chop!
return ret
end
def read_pendstr( dest = '' )
@pipe << "reading text...\n" if pre = @pipe ; @pipe = nil
rsize = 0
while (str = readuntil( CRLF )) != D_CRLF do
rsize += str.size
str.gsub!( /\A\./o, '' )
dest << str
end
@pipe << "read #{rsize} bytes\n" if @pipe = pre
return dest
end
def read_pendlist
@pipe << "reading list...\n" if pre = @pipe ; @pipe = nil
arr = []
str = nil
call = iterator?
while (str = readuntil( CRLF )) != D_CRLF do
str.chop!
arr.push str
yield str if iterator?
end
@pipe << "read #{arr.size} lines\n" if @pipe = pre
return arr
end
private
READ_BLOCK = 1024 * 8
def fill_rbuf
@buffer << @socket.sysread( READ_BLOCK )
end
def fetch_rbuf( len )
bsi = @buffer.size
ret = @buffer[ 0, len ]
@buffer = @buffer[ len, bsi - len ]
@pipe << %{read "#{debugstr ret}"\n} if @pipe
return ret
end
=begin
: write( src )
@ -506,6 +414,159 @@ Object
=end
class ProtocolSocket
def initialize( addr, port, pipe = nil )
@addr = addr
@port = port
@pipe = pipe
@closed = true
@ipaddr = ''
@sending = ''
@buffer = ''
@socket = TCPsocket.new( addr, port )
@closed = false
@ipaddr = @socket.addr[3]
end
attr :pipe, true
class << self
alias open new
end
def reopen
unless closed? then
@socket.close
flush_rbuf
end
@socket = TCPsocket.new( @addr, @port )
end
attr :socket, true
def close
@socket.close
@closed = true
end
def closed?
@closed
end
def address
@addr.dup
end
alias addr address
attr :port
def ip_address
@ipaddr.dup
end
alias ipaddr ip_address
attr :sending
CRLF = "\r\n"
D_CRLF = ".\r\n"
TERMEXP = /\n|\r\n|\r/o
def read( len, ret = '' )
@pipe << "reading #{len} bytes...\n" if pre = @pipe ; @pipe = nil
rsize = 0
while rsize + @buffer.size < len do
rsize += @buffer.size
ret << fetch_rbuf( @buffer.size )
fill_rbuf
end
ret << fetch_rbuf( len - rsize )
@pipe << "read #{len} bytes\n" if @pipe = pre
ret
end
def readuntil( target )
until idx = @buffer.index( target ) do
fill_rbuf
end
fetch_rbuf( idx + target.size )
end
def readline
ret = readuntil( CRLF )
ret.chop!
ret
end
def read_pendstr( dest = '' )
@pipe << "reading text...\n" if pre = @pipe ; @pipe = nil
rsize = 0
while (str = readuntil( CRLF )) != D_CRLF do
rsize += str.size
str.gsub!( /\A\./o, '' )
dest << str
end
@pipe << "read #{rsize} bytes\n" if @pipe = pre
dest
end
def read_pendlist
@pipe << "reading list...\n" if pre = @pipe ; @pipe = nil
arr = []
str = nil
call = iterator?
while (str = readuntil( CRLF )) != D_CRLF do
str.chop!
arr.push str
yield str if iterator?
end
@pipe << "read #{arr.size} lines\n" if @pipe = pre
arr
end
private
READ_BLOCK = 1024 * 8
def fill_rbuf
@buffer << @socket.sysread( READ_BLOCK )
end
def fetch_rbuf( len )
bsi = @buffer.size
ret = @buffer[ 0, len ]
@buffer = @buffer[ len, bsi - len ]
@pipe << %{read "#{Net.quote ret}"\n} if @pipe
ret
end
def flush_rbuf
@buffer = ''
end
public
@ -514,7 +575,7 @@ Object
each_crlf_line( src ) do |line|
do_write_do line
end
return do_write_fin
do_write_fin
end
@ -523,7 +584,7 @@ Object
src.each do |bin|
do_write_do bin
end
return do_write_fin
do_write_fin
end
@ -531,7 +592,7 @@ Object
do_write_beg
do_write_do str
do_write_do CRLF
return do_write_fin
do_write_fin
end
@ -547,7 +608,7 @@ Object
wsize = do_write_fin
@pipe << "wrote #{wsize} bytes text" if @pipe = pre
return wsize
wsize
end
@ -587,48 +648,41 @@ Object
def do_write_beg
@wtmp = 'write "' if @pipe
@writtensize = 0
@sending = ''
end
def do_write_do( arg )
@wtmp << debugstr( arg ) if @pipe
if @sending.size < 128 then
@sending << arg
if @pipe or @sending.size < 128 then
@sending << Net.quote( arg )
else
@sending << '...' unless @sending[-1] == ?.
end
s = @socket.write( arg )
@writtensize += s
return s
s
end
def do_write_fin
if @pipe then
@wtmp << "\n"
@pipe << @wtmp
@wtmp = nil
@pipe << 'write "'
@pipe << @sending
@pipe << "\"\n"
end
@socket.flush
return @writtensize
end
def debugstr( str )
ret = ''
while str and tmp = str[ 0, 50 ] do
str = str[ 50, str.size - 50 ]
tmp = tmp.inspect
ret << tmp[ 1, tmp.size - 2 ]
end
ret
@writtensize
end
end
end
def Net.quote( str )
str = str.gsub( "\n", '\\n' )
str.gsub!( "\r", '\\r' )
str.gsub!( "\t", '\\t' )
str
end
end # module Net

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

@ -1,11 +1,11 @@
=begin
= Net module version 1.0.3 reference manual
= net/smtp.rb
smtp.rb written by Minero Aoki <aamine@dp.u-netsurf.ne.jp>
written by Minero Aoki <aamine@dp.u-netsurf.ne.jp>
This library is distributed under the terms of Ruby style license.
You can freely redistribute/modify/copy this file.
This library is distributed under the terms of Ruby license.
You can freely distribute/modify this file.
=end
@ -13,6 +13,9 @@ You can freely redistribute/modify/copy this file.
require 'net/session'
module Net
=begin
== Net::SMTPSession
@ -27,18 +30,6 @@ Net::Session
This method create new SMTPSession object.
=end
module Net
class SMTPSession < Session
def proto_initialize
@proto_type = SMTPCommand
@port = 25
end
=begin
=== Methods
@ -65,26 +56,30 @@ module Net
=end
class SMTPSession < Session
Version = '1.1.0'
session_setvar :port, '25'
session_setvar :command_type, 'SMTPCommand'
def sendmail( mailsrc, fromaddr, toaddrs )
@proto.mailfrom( fromaddr )
@proto.rcpt( toaddrs )
@proto.mailfrom fromaddr
@proto.rcpt toaddrs
@proto.data
@proto.sendmail( mailsrc )
@proto.sendmail mailsrc
end
private
def do_start( helodom = nil )
def do_start( helodom = ENV['HOSTNAME'] )
unless helodom then
helodom = ENV[ 'HOSTNAME' ]
raise ArgumentError, "cannot get hostname"
end
@proto.helo( helodom )
end
def do_finish
@proto.quit
@proto.helo helodom
end
end
@ -111,17 +106,17 @@ Net::Command
: helo( helo_domain )
This method send "HELO" command and start SMTP session.<br>
This method send "HELO" command and start SMTP session.
helo_domain is localhost's FQDN.
: mailfrom( from_addr )
This method sends "MAIL FROM" command.<br>
This method sends "MAIL FROM" command.
from_addr is your mail address(????@????).
: rcpt( to_addrs )
This method sends "RCPT TO" command.<br>
This method sends "RCPT TO" command.
to_addrs is array of mail address(???@???) of destination.
: data( mailsrc )
@ -137,6 +132,12 @@ Net::Command
class SMTPCommand < Command
def initialize( sock )
super
check_reply SuccessCode
end
def helo( fromdom )
@socket.writeline( 'HELO ' << fromdom )
check_reply( SuccessCode )
@ -163,10 +164,11 @@ Net::Command
end
def sendmail( mailsrc )
def writemail( mailsrc )
@socket.write_pendstr( mailsrc )
check_reply( SuccessCode )
end
alias sendmail writemail
private
@ -211,9 +213,4 @@ Net::Command
end
unless Session::Version == '1.0.3' then
$stderr.puts "WARNING: wrong version of session.rb & smtp.rb"
end
end