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