mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
aamine
* lib/net/http.rb: add HTTP#request. * lib/net/http.rb: take HTTP 1.0 server into account (incomplete). * lib/net/protocol.rb: timeout for open/read. * lib/net/protocol.rb: add Protocol#on_connect,on_disconnect. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1160 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
765255b737
commit
cdc7602379
5 changed files with 344 additions and 316 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
Tue Feb 6 20:19:10 2001 Minero Aoki <aamine@dp.u-netsurf.ne.jp>
|
||||
|
||||
* lib/net/http.rb: add HTTP#request.
|
||||
|
||||
* lib/net/http.rb: take HTTP 1.0 server into account (incomplete).
|
||||
|
||||
* lib/net/protocol.rb: timeout for open/read.
|
||||
|
||||
* lib/net/protocol.rb: add Protocol#on_connect,on_disconnect.
|
||||
|
||||
Fri Feb 2 16:14:51 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||
|
||||
* array.c (rb_ary_sort_bang): returns self, even if its length is
|
||||
|
|
498
lib/net/http.rb
498
lib/net/http.rb
|
@ -14,7 +14,7 @@
|
|||
(Ruby Application Archive: http://www.ruby-lang.org/en/raa.html).
|
||||
|
||||
|
||||
= class HTTP
|
||||
= class Net::HTTP
|
||||
|
||||
== Class Methods
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
|||
HTTP default port (80).
|
||||
|
||||
|
||||
== Methods
|
||||
== Instance Methods
|
||||
|
||||
: start
|
||||
: start {|http| .... }
|
||||
|
@ -100,46 +100,31 @@
|
|||
|
||||
If called with block, gives a part of entity body string.
|
||||
|
||||
: new_get( path, header = nil ) {|req| .... }
|
||||
creates a new GET request object and gives it to the block.
|
||||
see also for Get class reference.
|
||||
|
||||
# example
|
||||
http.new_get( '/~foo/bar.html' ) do |req|
|
||||
req['accept'] = 'text/html'
|
||||
response = req.dispatch
|
||||
p response['Content-Type']
|
||||
puts response.read_header
|
||||
end
|
||||
: request( request, [src] )
|
||||
: request( request, [src] ) {|response| .... }
|
||||
sends REQUEST to (remote) http server. This method also writes
|
||||
string from SRC before it if REQUEST is a post/put request.
|
||||
(giving SRC for get/head request causes ArgumentError.)
|
||||
|
||||
: new_head( path, header = nil ) {|req| .... }
|
||||
creates a new HEAD request object and gives it to the block.
|
||||
see also Head class reference.
|
||||
|
||||
: new_post( path, header = nil ) {|req| .... }
|
||||
creates a new POST request object and gives it to the block.
|
||||
see also Post class reference.
|
||||
If called with block, gives a HTTP response object to the block.
|
||||
|
||||
|
||||
= class Get, Head, Post
|
||||
= class Net::HTTP::Get, Head, Post
|
||||
|
||||
HTTP request class. This class wraps request header and entity path.
|
||||
All "key" is case-insensitive.
|
||||
HTTP request classes. These classes wraps request header and
|
||||
entity path. All "key" is case-insensitive.
|
||||
|
||||
== Methods
|
||||
|
||||
: self[ key ]
|
||||
returns header field for "key".
|
||||
|
||||
: dispatch [only Get, Head]
|
||||
dispatches request.
|
||||
This method returns HTTPResponse object.
|
||||
: self[ key ] = val
|
||||
set header to "val".
|
||||
|
||||
: dispatch( data = '' ) [only Post]
|
||||
: dispatch {|adapter| .... } [only Post]
|
||||
dispatches request. "data" is
|
||||
|
||||
= class HTTPResponse
|
||||
= class Net::HTTPResponse
|
||||
|
||||
HTTP response class. This class wraps response header and entity.
|
||||
All "key" is case-insensitive.
|
||||
|
@ -209,13 +194,31 @@ module Net
|
|||
|
||||
class HTTP < Protocol
|
||||
|
||||
protocol_param :port, '80'
|
||||
|
||||
HTTPVersion = '1.1'
|
||||
|
||||
###
|
||||
### connection
|
||||
###
|
||||
|
||||
def addr_port
|
||||
address + (port == HTTP.port ? '' : ":#{port}")
|
||||
protocol_param :port, '80'
|
||||
|
||||
|
||||
def initialize( addr = nil, port = nil )
|
||||
super
|
||||
|
||||
@proxy_address = nil
|
||||
@proxy_port = nil
|
||||
|
||||
@curr_http_version = HTTPVersion
|
||||
@seems_1_0_server = false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def conn_command( sock )
|
||||
end
|
||||
|
||||
def do_finish
|
||||
end
|
||||
|
||||
|
||||
|
@ -223,11 +226,13 @@ module Net
|
|||
### proxy
|
||||
###
|
||||
|
||||
public
|
||||
|
||||
|
||||
class << self
|
||||
|
||||
def Proxy( p_addr, p_port = nil )
|
||||
::Net::NetPrivate::HTTPProxy.create_proxy_class(
|
||||
p_addr, p_port || self.port )
|
||||
ProxyMod.create_proxy_class( p_addr, p_port || self.port )
|
||||
end
|
||||
|
||||
alias orig_new new
|
||||
|
@ -274,9 +279,65 @@ module Net
|
|||
end
|
||||
|
||||
|
||||
###
|
||||
### for compatibility
|
||||
###
|
||||
module ProxyMod
|
||||
|
||||
class << self
|
||||
|
||||
def create_proxy_class( p_addr, p_port )
|
||||
klass = Class.new( HTTP )
|
||||
klass.module_eval {
|
||||
include HTTPProxy
|
||||
@proxy_address = p_addr
|
||||
@proxy_port = p_port
|
||||
}
|
||||
def klass.proxy_class?
|
||||
true
|
||||
end
|
||||
|
||||
def klass.proxy_address
|
||||
@proxy_address
|
||||
end
|
||||
|
||||
def klass.proxy_port
|
||||
@proxy_port
|
||||
end
|
||||
|
||||
klass
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def initialize( addr, port )
|
||||
super
|
||||
@proxy_address = type.proxy_address
|
||||
@proxy_port = type.proxy_port
|
||||
end
|
||||
|
||||
attr_reader :proxy_address, :proxy_port
|
||||
|
||||
alias proxyaddr proxy_address
|
||||
alias proxyport proxy_port
|
||||
|
||||
def proxy?
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def conn_socket( addr, port )
|
||||
super @proxy_address, @proxy_port
|
||||
end
|
||||
|
||||
def edit_path( path )
|
||||
'http://' + addr_port + path
|
||||
end
|
||||
|
||||
end # module ProxyMod
|
||||
|
||||
|
||||
#
|
||||
# for backward compatibility
|
||||
#
|
||||
|
||||
@@newimpl = true
|
||||
|
||||
|
@ -300,23 +361,26 @@ module Net
|
|||
end
|
||||
|
||||
|
||||
###
|
||||
### http operations
|
||||
###
|
||||
#
|
||||
# http operations
|
||||
#
|
||||
|
||||
def self.defrequest( nm, hasdest, hasdata )
|
||||
public
|
||||
|
||||
def self.def_http_method( nm, hasdest, hasdata )
|
||||
name = nm.id2name.downcase
|
||||
cname = nm.id2name
|
||||
lineno = __LINE__ + 2
|
||||
src = <<S
|
||||
src = <<" ----"
|
||||
|
||||
def #{name}( path, #{hasdata ? 'data,' : ''}
|
||||
u_header = nil #{hasdest ? ',dest = nil, &block' : ''} )
|
||||
resp = #{name}2( path,
|
||||
#{hasdata ? 'data,' : ''}
|
||||
u_header ) {|resp|
|
||||
resp = nil
|
||||
request(
|
||||
#{cname}.new( path, u_header ) #{hasdata ? ',data' : ''}
|
||||
) do |resp|
|
||||
resp.read_body( #{hasdest ? 'dest, &block' : ''} )
|
||||
}
|
||||
end
|
||||
if @newimpl then
|
||||
resp
|
||||
else
|
||||
|
@ -326,78 +390,63 @@ module Net
|
|||
end
|
||||
|
||||
def #{name}2( path, #{hasdata ? 'data,' : ''}
|
||||
u_header = nil )
|
||||
new_#{name}( path, u_header ) do |req|
|
||||
resp = req.dispatch#{hasdata ? '(data)' : ''}
|
||||
yield resp if block_given?
|
||||
end
|
||||
u_header = nil, &block )
|
||||
request( #{cname}.new(path, u_header),
|
||||
#{hasdata ? 'data,' : ''} &block )
|
||||
end
|
||||
|
||||
def new_#{name}( path, u_header = nil, &block )
|
||||
common_oper ::Net::NetPrivate::#{cname}, path, u_header, &block
|
||||
end
|
||||
S
|
||||
# puts src
|
||||
----
|
||||
#puts src
|
||||
module_eval src, __FILE__, lineno
|
||||
end
|
||||
|
||||
def_http_method :Get, true, false
|
||||
def_http_method :Head, false, false
|
||||
def_http_method :Post, true, true
|
||||
def_http_method :Put, false, true
|
||||
|
||||
defrequest :Get, true, false
|
||||
defrequest :Head, false, false
|
||||
defrequest :Post, true, true
|
||||
defrequest :Put, false, true
|
||||
def request( req, *args )
|
||||
common_oper( req ) {
|
||||
req.__send__( :exec,
|
||||
@socket, @curr_http_version,
|
||||
edit_path(req.path),
|
||||
header_defaults, *args )
|
||||
yield req.response if block_given?
|
||||
}
|
||||
req.response
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
def initialize( addr = nil, port = nil )
|
||||
super
|
||||
@command = ::Net::NetPrivate::Switch.new
|
||||
@curr_http_version = HTTPVersion
|
||||
end
|
||||
|
||||
def connect( addr = @address, port = @port )
|
||||
@socket = type.socket_type.open( addr, port, @pipe )
|
||||
end
|
||||
|
||||
def disconnect
|
||||
if @socket and not @socket.closed? then
|
||||
@socket.close
|
||||
end
|
||||
@socket = nil
|
||||
end
|
||||
|
||||
def do_finish
|
||||
end
|
||||
|
||||
|
||||
def common_oper( reqc, path, u_header )
|
||||
req = nil
|
||||
|
||||
@command.on
|
||||
def common_oper( req )
|
||||
if not @socket then
|
||||
start
|
||||
req['connection'] = 'close'
|
||||
elsif @socket.closed? then
|
||||
@socket.reopen
|
||||
end
|
||||
if @seems_1_0_server then
|
||||
req['connection'] = 'close'
|
||||
end
|
||||
|
||||
req = reqc.new( @curr_http_version,
|
||||
@socket, inihead,
|
||||
edit_path(path), u_header )
|
||||
yield req if block_given?
|
||||
req.terminate
|
||||
yield req
|
||||
req.response.__send__ :terminate
|
||||
@curr_http_version = req.http_version
|
||||
|
||||
unless keep_alive? req, req.response then
|
||||
if keep_alive? req, req.response then
|
||||
if @socket.closed? then
|
||||
@seems_1_0_server = true
|
||||
@socket.close
|
||||
end
|
||||
else
|
||||
@socket.close
|
||||
end
|
||||
@command.off
|
||||
|
||||
req.response
|
||||
end
|
||||
|
||||
def inihead
|
||||
def header_defaults
|
||||
h = {}
|
||||
h['Host'] = addr_port
|
||||
h['Connection'] = 'Keep-Alive'
|
||||
|
@ -427,89 +476,16 @@ S
|
|||
false
|
||||
end
|
||||
|
||||
def addr_port
|
||||
address + (port == HTTP.port ? '' : ":#{port}")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
HTTPSession = HTTP
|
||||
|
||||
|
||||
|
||||
module NetPrivate
|
||||
|
||||
class Switch
|
||||
def initialize
|
||||
@critical = false
|
||||
end
|
||||
|
||||
def critical?
|
||||
@critical
|
||||
end
|
||||
|
||||
def on
|
||||
@critical = true
|
||||
end
|
||||
|
||||
def off
|
||||
@critical = false
|
||||
end
|
||||
end
|
||||
|
||||
module HTTPProxy
|
||||
|
||||
class << self
|
||||
|
||||
def create_proxy_class( p_addr, p_port )
|
||||
klass = Class.new( HTTP )
|
||||
klass.module_eval {
|
||||
include HTTPProxy
|
||||
@proxy_address = p_addr
|
||||
@proxy_port = p_port
|
||||
}
|
||||
def klass.proxy_class?
|
||||
true
|
||||
end
|
||||
|
||||
def klass.proxy_address
|
||||
@proxy_address
|
||||
end
|
||||
|
||||
def klass.proxy_port
|
||||
@proxy_port
|
||||
end
|
||||
|
||||
klass
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
def initialize( addr, port )
|
||||
super
|
||||
@proxy_address = type.proxy_address
|
||||
@proxy_port = type.proxy_port
|
||||
end
|
||||
|
||||
attr_reader :proxy_address, :proxy_port
|
||||
|
||||
alias proxyaddr proxy_address
|
||||
alias proxyport proxy_port
|
||||
|
||||
def proxy?
|
||||
true
|
||||
end
|
||||
|
||||
def connect( addr = nil, port = nil )
|
||||
super @proxy_address, @proxy_port
|
||||
end
|
||||
|
||||
def edit_path( path )
|
||||
'http://' + addr_port + path
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end # net private
|
||||
|
||||
|
||||
class Code
|
||||
|
||||
def http_mkchild( bodyexist = nil )
|
||||
|
@ -575,8 +551,7 @@ S
|
|||
|
||||
|
||||
|
||||
module NetPrivate
|
||||
|
||||
class HTTP
|
||||
|
||||
###
|
||||
### request
|
||||
|
@ -584,15 +559,10 @@ S
|
|||
|
||||
class HTTPRequest
|
||||
|
||||
def initialize( httpver, sock, inith, path, uhead )
|
||||
@http_version = httpver
|
||||
@socket = sock
|
||||
def initialize( path, uhead = nil )
|
||||
@path = path
|
||||
@response = nil
|
||||
|
||||
@u_header = inith
|
||||
@u_header = tmp = {}
|
||||
return unless uhead
|
||||
tmp = {}
|
||||
uhead.each do |k,v|
|
||||
key = canonical(k)
|
||||
if tmp.key? key then
|
||||
|
@ -600,13 +570,17 @@ S
|
|||
end
|
||||
tmp[ key ] = v.strip
|
||||
end
|
||||
@u_header.update tmp
|
||||
|
||||
@socket = nil
|
||||
@response = nil
|
||||
@http_version = nil
|
||||
end
|
||||
|
||||
attr_reader :http_version
|
||||
public
|
||||
|
||||
attr_reader :path
|
||||
attr_reader :response
|
||||
attr_reader :http_version
|
||||
|
||||
def inspect
|
||||
"\#<#{type}>"
|
||||
|
@ -640,38 +614,42 @@ S
|
|||
@u_header.each_value( &block )
|
||||
end
|
||||
|
||||
|
||||
def terminate
|
||||
@response.terminate
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
def canonical( k )
|
||||
k.split('-').collect {|i| i.capitalize }.join('-')
|
||||
end
|
||||
|
||||
#
|
||||
# write
|
||||
#
|
||||
|
||||
# write request & header
|
||||
|
||||
def do_dispatch
|
||||
if @response then
|
||||
raise IOError, "#{type}\#dispatch called twice"
|
||||
end
|
||||
yield
|
||||
@response = read_response
|
||||
def exec( sock, ver, path, ihead )
|
||||
ready( sock, ihead ) {|header|
|
||||
request ver, path, header
|
||||
}
|
||||
end
|
||||
|
||||
def request( req )
|
||||
@socket.writeline req
|
||||
@u_header.each do |n,v|
|
||||
def ready( sock, ihead )
|
||||
@response = nil
|
||||
@socket = sock
|
||||
ihead.update @u_header
|
||||
yield ihead
|
||||
@response = read_response
|
||||
@sock = nil
|
||||
end
|
||||
|
||||
def request( ver, path, header )
|
||||
@socket.writeline sprintf('%s %s HTTP/%s', type::METHOD, path, ver)
|
||||
header.each do |n,v|
|
||||
@socket.writeline n + ': ' + v
|
||||
end
|
||||
@socket.writeline ''
|
||||
end
|
||||
|
||||
# read response & header
|
||||
#
|
||||
# read
|
||||
#
|
||||
|
||||
def read_response
|
||||
resp = rdresp0
|
||||
|
@ -683,13 +661,12 @@ S
|
|||
resp = get_resline
|
||||
|
||||
while true do
|
||||
line = @socket.readline
|
||||
line = @socket.readuntil( "\n", true ) # ignore EOF
|
||||
line.sub!( /\s+\z/, '' ) # don't use chop!
|
||||
break if line.empty?
|
||||
|
||||
m = /\A([^:]+):\s*/.match( line )
|
||||
unless m then
|
||||
raise HTTPBadResponse, 'wrong header line format'
|
||||
end
|
||||
m or raise HTTPBadResponse, 'wrong header line format'
|
||||
nm = m[1]
|
||||
line = m.post_match
|
||||
if resp.key? nm then
|
||||
|
@ -704,7 +681,7 @@ S
|
|||
|
||||
def get_resline
|
||||
str = @socket.readline
|
||||
m = /\AHTTP\/(\d+\.\d+)?\s+(\d\d\d)\s*(.*)\z/i.match( str )
|
||||
m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)\s*(.*)\z/i.match( str )
|
||||
unless m then
|
||||
raise HTTPBadResponse, "wrong status line: #{str}"
|
||||
end
|
||||
|
@ -712,52 +689,32 @@ S
|
|||
status = m[2]
|
||||
discrip = m[3]
|
||||
|
||||
HTTPResponse.new( status, discrip, @socket, type::HAS_BODY )
|
||||
::Net::NetPrivate::HTTPResponse.new(
|
||||
status, discrip, @socket, type::HAS_BODY )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Get < HTTPRequest
|
||||
|
||||
HAS_BODY = true
|
||||
|
||||
def dispatch
|
||||
do_dispatch {
|
||||
request sprintf('GET %s HTTP/%s', @path, @http_version)
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Head < HTTPRequest
|
||||
|
||||
HAS_BODY = false
|
||||
|
||||
def dispatch
|
||||
do_dispatch {
|
||||
request sprintf('HEAD %s HTTP/%s', @path, @http_version)
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class HTTPRequestWithData < HTTPRequest
|
||||
|
||||
private
|
||||
|
||||
def dispatch( str = nil )
|
||||
def exec( sock, ver, path, ihead, str = nil )
|
||||
check_arg str, block_given?
|
||||
|
||||
if block_given? then
|
||||
ac = Accumulator.new
|
||||
yield ac # must be yield, not block.call
|
||||
yield ac # must be yield, DO NOT USE block.call
|
||||
data = ac.terminate
|
||||
else
|
||||
data = str
|
||||
end
|
||||
|
||||
do_dispatch {
|
||||
@u_header['Content-Length'] = data.size.to_s
|
||||
@u_header.delete 'Transfer-Encoding'
|
||||
request sprintf('%s %s HTTP/%s', type::METHOD, @path, @http_version)
|
||||
ready( sock, ihead ) {|header|
|
||||
header['Content-Length'] = data.size.to_s
|
||||
header.delete 'Transfer-Encoding'
|
||||
request ver, path, header
|
||||
@socket.write data
|
||||
}
|
||||
end
|
||||
|
@ -773,21 +730,6 @@ S
|
|||
|
||||
end
|
||||
|
||||
class Post < HTTPRequestWithData
|
||||
|
||||
HAS_BODY = true
|
||||
|
||||
METHOD = 'POST'
|
||||
|
||||
end
|
||||
|
||||
class Put < HTTPRequestWithData
|
||||
|
||||
HAS_BODY = true
|
||||
|
||||
METHOD = 'PUT'
|
||||
|
||||
end
|
||||
|
||||
class Accumulator
|
||||
|
||||
|
@ -810,6 +752,31 @@ S
|
|||
end
|
||||
|
||||
|
||||
class Get < HTTPRequest
|
||||
HAS_BODY = true
|
||||
METHOD = 'GET'
|
||||
end
|
||||
|
||||
class Head < HTTPRequest
|
||||
HAS_BODY = false
|
||||
METHOD = 'HEAD'
|
||||
end
|
||||
|
||||
class Post < HTTPRequestWithData
|
||||
HAS_BODY = true
|
||||
METHOD = 'POST'
|
||||
end
|
||||
|
||||
class Put < HTTPRequestWithData
|
||||
HAS_BODY = true
|
||||
METHOD = 'PUT'
|
||||
end
|
||||
|
||||
end # HTTP::
|
||||
|
||||
|
||||
|
||||
module NetPrivate
|
||||
|
||||
###
|
||||
### response
|
||||
|
@ -926,7 +893,9 @@ S
|
|||
end
|
||||
|
||||
|
||||
#
|
||||
# header (for backward compatibility)
|
||||
#
|
||||
|
||||
def read_header
|
||||
self
|
||||
|
@ -935,8 +904,9 @@ S
|
|||
alias header read_header
|
||||
alias response read_header
|
||||
|
||||
|
||||
#
|
||||
# body
|
||||
#
|
||||
|
||||
def read_body( dest = nil, &block )
|
||||
if @read and (dest or block) then
|
||||
|
@ -963,22 +933,20 @@ S
|
|||
alias entity read_body
|
||||
|
||||
|
||||
# internal use only
|
||||
private
|
||||
|
||||
|
||||
def terminate
|
||||
read_body
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
def read_body_0( dest )
|
||||
if chunked? then
|
||||
read_chunked dest
|
||||
else
|
||||
clen = content_length
|
||||
if clen then
|
||||
@socket.read clen, dest
|
||||
@socket.read clen, dest, true # ignore EOF
|
||||
else
|
||||
clen = range_length
|
||||
if clen then
|
||||
|
@ -1066,6 +1034,18 @@ S
|
|||
end
|
||||
|
||||
|
||||
class Dummy
|
||||
|
||||
def initialize( *args )
|
||||
end
|
||||
|
||||
def critical?
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end # module Net::NetPrivate
|
||||
|
||||
end # module Net
|
||||
|
|
|
@ -65,7 +65,7 @@ Net::Protocol
|
|||
m.pop file
|
||||
end
|
||||
|
||||
=== Methods
|
||||
=== Instance Methods
|
||||
|
||||
: start( account, password )
|
||||
: start( account, password ) {|pop| .... }
|
||||
|
|
|
@ -15,7 +15,7 @@ You can get it from RAA
|
|||
|
||||
== Net::Protocol
|
||||
|
||||
the abstract class for Internet protocol
|
||||
the abstract class for some internet protocols
|
||||
|
||||
=== Super Class
|
||||
|
||||
|
@ -59,6 +59,7 @@ Object
|
|||
=end
|
||||
|
||||
require 'socket'
|
||||
require 'timeout'
|
||||
|
||||
|
||||
module Net
|
||||
|
@ -116,8 +117,12 @@ module Net
|
|||
@command = nil
|
||||
@socket = nil
|
||||
|
||||
@active = false
|
||||
@pipe = nil
|
||||
@active = false
|
||||
|
||||
@open_timeout = nil
|
||||
@read_timeout = nil
|
||||
|
||||
@pipe = nil
|
||||
end
|
||||
|
||||
attr_reader :address
|
||||
|
@ -126,10 +131,24 @@ module Net
|
|||
attr_reader :command
|
||||
attr_reader :socket
|
||||
|
||||
attr_accessor :open_timeout
|
||||
attr_accessor :read_timeout
|
||||
|
||||
def active?
|
||||
@active
|
||||
end
|
||||
|
||||
def set_pipe( arg ) # un-documented
|
||||
@pipe = arg
|
||||
end
|
||||
|
||||
def inspect
|
||||
"#<#{type} #{address}:#{port} open=#{active?}>"
|
||||
end
|
||||
|
||||
#
|
||||
# open session
|
||||
#
|
||||
|
||||
def start( *args )
|
||||
return false if active?
|
||||
|
@ -146,53 +165,66 @@ module Net
|
|||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _start( args )
|
||||
connect
|
||||
do_start( *args )
|
||||
@active = true
|
||||
end
|
||||
private :_start
|
||||
|
||||
def connect
|
||||
conn_socket @address, @port
|
||||
conn_command @socket
|
||||
on_connect
|
||||
end
|
||||
|
||||
def conn_socket( addr, port )
|
||||
@socket = type.socket_type.open(
|
||||
addr, port, @open_timeout, @read_timeout, @pipe )
|
||||
end
|
||||
|
||||
def conn_command( sock )
|
||||
@command = type.command_type.new( sock )
|
||||
end
|
||||
|
||||
def on_connect
|
||||
end
|
||||
|
||||
def do_start
|
||||
end
|
||||
|
||||
#
|
||||
# close session
|
||||
#
|
||||
|
||||
public
|
||||
|
||||
def finish
|
||||
return false unless active?
|
||||
|
||||
do_finish unless @command.critical?
|
||||
do_finish if @command and not @command.critical?
|
||||
disconnect
|
||||
@active = false
|
||||
true
|
||||
end
|
||||
|
||||
def active?
|
||||
@active
|
||||
end
|
||||
|
||||
def set_pipe( arg ) # un-documented
|
||||
@pipe = arg
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
def do_start
|
||||
end
|
||||
|
||||
def do_finish
|
||||
@command.quit
|
||||
end
|
||||
|
||||
|
||||
def connect( addr = @address, port = @port )
|
||||
@socket = type.socket_type.open( addr, port, @pipe )
|
||||
@command = type.command_type.new( @socket )
|
||||
end
|
||||
|
||||
def disconnect
|
||||
@command = nil
|
||||
if @socket and not @socket.closed? then
|
||||
@socket.close
|
||||
end
|
||||
@socket = nil
|
||||
@socket = nil
|
||||
on_disconnect
|
||||
end
|
||||
|
||||
def on_disconnect
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -311,6 +343,7 @@ module Net
|
|||
def write( str )
|
||||
@sock.__send__ @mid, str
|
||||
end
|
||||
|
||||
alias << write
|
||||
|
||||
end
|
||||
|
@ -407,6 +440,7 @@ module Net
|
|||
@critical = false
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def critical
|
||||
|
@ -431,9 +465,12 @@ module Net
|
|||
|
||||
class Socket
|
||||
|
||||
def initialize( addr, port, pipe = nil )
|
||||
def initialize( addr, port, otime = nil, rtime = nil, pipe = nil )
|
||||
@addr = addr
|
||||
@port = port
|
||||
|
||||
@read_timeout = rtime
|
||||
|
||||
@pipe = pipe
|
||||
@prepipe = nil
|
||||
|
||||
|
@ -442,7 +479,9 @@ module Net
|
|||
@sending = ''
|
||||
@buffer = ''
|
||||
|
||||
@socket = TCPsocket.new( addr, port )
|
||||
timeout( otime ) {
|
||||
@socket = TCPsocket.new( addr, port )
|
||||
}
|
||||
@closed = false
|
||||
@ipaddr = @socket.addr[3]
|
||||
end
|
||||
|
@ -494,13 +533,15 @@ module Net
|
|||
attr_reader :sending
|
||||
|
||||
|
||||
###
|
||||
### read
|
||||
###
|
||||
#
|
||||
# read
|
||||
#
|
||||
|
||||
public
|
||||
|
||||
CRLF = "\r\n"
|
||||
|
||||
def read( len, dest = '' )
|
||||
def read( len, dest = '', ignerr = false )
|
||||
@pipe << "reading #{len} bytes...\n" if @pipe; pipeoff
|
||||
|
||||
rsize = 0
|
||||
|
@ -509,16 +550,15 @@ module Net
|
|||
rsize += writeinto( dest, @buffer.size )
|
||||
fill_rbuf
|
||||
end
|
||||
writeinto( dest, len - rsize )
|
||||
rescue EOFError
|
||||
len = rsize
|
||||
raise unless igneof
|
||||
end
|
||||
writeinto( dest, len - rsize )
|
||||
|
||||
@pipe << "read #{len} bytes\n" if pipeon
|
||||
dest
|
||||
end
|
||||
|
||||
|
||||
def read_all( dest = '' )
|
||||
@pipe << "reading all...\n" if @pipe; pipeoff
|
||||
|
||||
|
@ -536,8 +576,7 @@ module Net
|
|||
dest
|
||||
end
|
||||
|
||||
|
||||
def readuntil( target )
|
||||
def readuntil( target, igneof = false )
|
||||
dest = ''
|
||||
begin
|
||||
while true do
|
||||
|
@ -547,11 +586,11 @@ module Net
|
|||
end
|
||||
writeinto( dest, idx + target.size )
|
||||
rescue EOFError
|
||||
raise unless igneof
|
||||
writeinto( dest, @buffer.size )
|
||||
end
|
||||
dest
|
||||
end
|
||||
|
||||
|
||||
def readline
|
||||
ret = readuntil( "\n" )
|
||||
|
@ -559,7 +598,6 @@ module Net
|
|||
ret
|
||||
end
|
||||
|
||||
|
||||
def read_pendstr( dest )
|
||||
@pipe << "reading text...\n" if @pipe; pipeoff
|
||||
|
||||
|
@ -574,7 +612,6 @@ module Net
|
|||
dest
|
||||
end
|
||||
|
||||
|
||||
# private use only (can not handle 'break')
|
||||
def read_pendlist
|
||||
@pipe << "reading list...\n" if @pipe; pipeoff
|
||||
|
@ -594,10 +631,17 @@ module Net
|
|||
private
|
||||
|
||||
|
||||
READ_BLOCK = 1024 * 8
|
||||
READ_SIZE = 1024 * 4
|
||||
|
||||
def fill_rbuf
|
||||
@buffer << @socket.sysread( READ_BLOCK )
|
||||
unless IO.select [@socket], nil, nil, @read_timeout then
|
||||
on_read_timeout
|
||||
end
|
||||
@buffer << @socket.sysread( READ_SIZE )
|
||||
end
|
||||
|
||||
def on_read_timeout
|
||||
raise TimeoutError, "socket read timeout (#{@read_timeout} sec)"
|
||||
end
|
||||
|
||||
def writeinto( dest, len )
|
||||
|
@ -610,20 +654,18 @@ module Net
|
|||
end
|
||||
|
||||
|
||||
###
|
||||
### write
|
||||
###
|
||||
#
|
||||
# write interfece
|
||||
#
|
||||
|
||||
public
|
||||
|
||||
|
||||
def write( str )
|
||||
writing {
|
||||
do_write str
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def writeline( str )
|
||||
writing {
|
||||
do_write str
|
||||
|
@ -631,7 +673,6 @@ module Net
|
|||
}
|
||||
end
|
||||
|
||||
|
||||
def write_bin( src, block )
|
||||
writing {
|
||||
if block then
|
||||
|
@ -644,7 +685,6 @@ module Net
|
|||
}
|
||||
end
|
||||
|
||||
|
||||
def write_pendstr( src, block )
|
||||
@pipe << "writing text from #{src.type}\n" if @pipe; pipeoff
|
||||
|
||||
|
|
|
@ -30,10 +30,8 @@ Net::Protocol
|
|||
|
||||
=== Methods
|
||||
|
||||
: start( helo_domain = Socket.gethostname, \
|
||||
account = nil, password = nil, authtype = nil )
|
||||
: start( helo_domain = Socket.gethostname, \
|
||||
account = nil, password = nil, authtype = nil ) {|smtp| .... }
|
||||
: start( helo_domain = Socket.gethostname, account = nil, password = nil, authtype = nil )
|
||||
: start( helo_domain = Socket.gethostname, account = nil, password = nil, authtype = nil ) {|smtp| .... }
|
||||
opens TCP connection and starts SMTP session.
|
||||
If protocol had been started, do nothing and return false.
|
||||
|
||||
|
@ -53,10 +51,10 @@ Net::Protocol
|
|||
to_addrs must be a String(s) or an Array of String.
|
||||
|
||||
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)
|
||||
* Net::ProtoSyntaxError: syntax error (errno.500)
|
||||
* Net::ProtoFatalError: fatal error (errno.550)
|
||||
* Net::ProtoUnknownError: unknown error
|
||||
* Net::ProtoServerBusy: temporary error (errno.420/450)
|
||||
|
||||
# usage example
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue