* lib/net/protocol.rb: clear read buffer after reopen.
* lib/net/protocol.rb: refactoring.
* lib/net/http.rb: split module HTTPHeader from HTTPResponse.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1209 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
aamine 2001-02-22 23:23:57 +00:00
parent d633fc6b5b
commit acce0b7ec4
3 changed files with 229 additions and 148 deletions

View File

@ -1,3 +1,11 @@
Fri Feb 23 08:28:58 2001 Minero Aoki <aamine@dp.u-netsurf.ne.jp>
* lib/net/protocol.rb: clear read buffer after reopen.
* lib/net/protocol.rb: refactoring.
* lib/net/http.rb: split module HTTPHeader from HTTPResponse.
Tue Feb 20 23:45:35 2001 WATANABE Hirofumi <eban@ruby-lang.org>
* process.c: add W* macro if not available.

View File

@ -26,8 +26,17 @@
: start( address = 'localhost', port = 80, proxy_addr = nil, proxy_port = nil )
: start( address = 'localhost', port = 80, proxy_addr = nil, proxy_port = nil ) {|http| .... }
is equals to
Net::HTTP.new( address, port, proxy_addr, proxy_port ).start(&block)
: get( address, path, port = 80 )
gets entity body from path and returns it.
return value is a String.
: get_print( address, path, port = 80 )
gets entity body from path and print it.
return value is an entity body (a String).
: Proxy( address, port )
creates a HTTP proxy class.
Arguments are address/port of proxy host.
@ -190,6 +199,7 @@ require 'net/protocol'
module Net
class HTTPBadResponse < StandardError; end
class HTTPHeaderSyntaxError < StandardError; end
class HTTP < Protocol
@ -396,7 +406,6 @@ module Net
#{hasdata ? 'data,' : ''} &block )
end
----
#puts src
module_eval src, __FILE__, lineno
end
@ -449,9 +458,9 @@ module Net
def header_defaults
h = {}
h['Host'] = addr_port
h['Connection'] = 'Keep-Alive'
h['Accept'] = '*/*'
h['host'] = addr_port
h['connection'] = 'Keep-Alive'
h['accept'] = '*/*'
h
end
@ -481,6 +490,24 @@ module Net
address + (port == HTTP.port ? '' : ":#{port}")
end
#
# utils
#
def self.get( addr, path, port = nil )
req = Get.new( path )
resp = nil
new( addr, port || HTTP.port ).start {|http|
resp = http.request( req )
}
resp.body
end
def self.get_print( addr, path, port = nil )
print get( addr, path, port )
end
end
HTTPSession = HTTP
@ -558,14 +585,147 @@ module Net
net_private {
module HTTPHeader
def size
@header.size
end
alias length size
def []( key )
@header[ key.downcase ]
end
def []=( key, val )
@header[ key.downcase ] = val
end
def each( &block )
@header.each( &block )
end
def each_key( &block )
@header.each_key( &block )
end
def each_value( &block )
@header.each_value( &block )
end
def delete( key )
@header.delete key.downcase
end
def key?( key )
@header.key? key.downcase
end
def to_hash
@header.dup
end
def canonical_each
@header.each do |k,v|
yield canonical(k), v
end
end
def canonical( k )
k.split('-').collect {|i| i.capitalize }.join('-')
end
def range
s = @header['range']
s or return nil
arr = []
s.split(',').each do |spec|
m = /bytes\s*=\s*(\d+)?\s*-\s*(\d+)?/i.match( spec )
m or raise HTTPHeaderSyntaxError, "wrong Range: #{spec}"
d1 = m[1].to_i
d2 = m[2].to_i
if m[1] and m[2] then arr.push d1 .. d2
elsif m[1] then arr.push d1 .. -1
elsif m[2] then arr.push -d2 .. -1
else
raise HTTPHeaderSyntaxError, 'range is not specified'
end
end
return *arr
end
def range=( r )
case r
when Numeric
s = r > 0 ? "0-#{r - 1}" : "-#{-r}"
when Range
first = r.first
last = r.last
if r.exclude_end? then
last -= 1
end
if last == -1 then
s = first > 0 ? "#{first}-" : "-#{-first}"
else
first >= 0 or raise HTTPHeaderSyntaxError, 'range.first is negative'
last > 0 or raise HTTPHeaderSyntaxError, 'range.last is negative'
first < last or raise HTTPHeaderSyntaxError, 'must be .first < .last'
s = "#{first}-#{last}"
end
else
raise TypeError, 'Range/Integer is required'
end
@header['range'] = "bytes=#{s}"
r
end
def content_length
s = @header['content-length']
s or return nil
m = /\d+/.match(s)
m or raise HTTPHeaderSyntaxError, 'wrong Content-Length format'
m[0].to_i
end
def chunked?
s = @header['transfer-encoding']
s and /(?:\A|[^\-\w])chunked(?:[^\-\w]|\z)/i === s
end
def content_range
s = @header['content-range']
s or return nil
m = %r<bytes\s+(\d+)-(\d+)/(?:\d+|\*)>i.match( s )
m or raise HTTPHeaderSyntaxError, 'wrong Content-Range format'
m[1].to_i .. m[2].to_i + 1
end
def range_length
r = content_range
r and r.length
end
end
class HTTPRequest
include ::Net::NetPrivate::HTTPHeader
def initialize( path, uhead = nil )
@path = path
@u_header = tmp = {}
@header = tmp = {}
return unless uhead
uhead.each do |k,v|
key = canonical(k)
key = k.downcase
if tmp.key? key then
$stderr.puts "WARNING: duplicated HTTP header: #{k}" if $VERBOSE
end
@ -583,41 +743,9 @@ module Net
"\#<#{type}>"
end
def []( key )
@u_header[ canonical key ]
end
def []=( key, val )
@u_header[ canonical key ] = val
end
def key?( key )
@u_header.key? canonical(key)
end
def delete( key )
@u_header.delete canonical(key)
end
def each( &block )
@u_header.each( &block )
end
def each_key( &block )
@u_header.each_key( &block )
end
def each_value( &block )
@u_header.each_value( &block )
end
private
def canonical( k )
k.split('-').collect {|i| i.capitalize }.join('-')
end
#
# write
#
@ -632,7 +760,7 @@ module Net
def ready( sock, ihead )
@response = nil
@socket = sock
ihead.update @u_header
ihead.update @header
yield ihead
@response = get_response
@sock = nil
@ -641,7 +769,7 @@ module Net
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 canonical(n) + ': ' + v
end
@socket.writeline ''
end
@ -682,9 +810,7 @@ module Net
def get_resline
str = @socket.readline
m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)\s*(.*)\z/i.match( str )
unless m then
raise HTTPBadResponse, "wrong status line: #{str}"
end
m or raise HTTPBadResponse, "wrong status line: #{str}"
httpver = m[1]
status = m[2]
discrip = m[3]
@ -789,6 +915,8 @@ module Net
class HTTPResponse < Response
include ::Net::NetPrivate::HTTPHeader
CODE_CLASS_TO_OBJ = {
'1' => HTTPInformationCode,
'2' => HTTPSuccessCode,
@ -841,7 +969,6 @@ module Net
'505' => HTTPVersionNotSupported
}
def initialize( stat, msg, sock, be, hv )
code = CODE_TO_OBJ[stat] ||
CODE_CLASS_TO_OBJ[stat[0,1]] ||
@ -862,38 +989,6 @@ module Net
"#<#{type} #{code}>"
end
def []( key )
@header[ key.downcase ]
end
def []=( key, val )
@header[ key.downcase ] = val
end
def each( &block )
@header.each( &block )
end
def each_key( &block )
@header.each_key( &block )
end
def each_value( &block )
@header.each_value( &block )
end
def delete( key )
@header.delete key.downcase
end
def key?( key )
@header.key? key.downcase
end
def to_hash
@header.dup
end
def value
unless SuccessCode === self then
error! self
@ -973,9 +1068,7 @@ module Net
while true do
line = @socket.readline
m = /[0-9a-fA-F]+/.match( line )
unless m then
raise HTTPBadResponse, "wrong chunk size line: #{line}"
end
m or raise HTTPBadResponse, "wrong chunk size line: #{line}"
len = m[0].hex
break if len == 0
@socket.read( len, dest ); total += len
@ -986,37 +1079,6 @@ module Net
end
end
def content_length
if @header.key? 'content-length' then
m = /\d+/.match( @header['content-length'] )
unless m then
raise HTTPBadResponse, 'wrong Content-Length format'
end
m[0].to_i
else
nil
end
end
def chunked?
tmp = @header['transfer-encoding']
tmp and /\bchunked\b/i === tmp
end
def range_length
s = @header['content-range']
s or return nil
m = %r<bytes\s+(\d+)-(\d+)/(?:\d+|\*)>.match( s )
m or raise HTTPBadResponse, 'wrong Content-Range format'
low = m[1].to_i
up = m[2].to_i
return nil if low > up
up - low + 1
end
def stream_check
if @socket.closed? then
raise IOError, 'try to read body out of block'
@ -1025,8 +1087,7 @@ module Net
def procdest( dest, block )
if dest and block then
raise ArgumentError,
'both of arg and block are given for HTTP method'
raise ArgumentError, 'both of arg and block are given for HTTP method'
end
if block then
::Net::NetPrivate::ReadAdapter.new block

View File

@ -490,18 +490,22 @@ module Net
@debugout = dout
@closed = true
@ipaddr = ''
@socket = nil
@sending = ''
@buffer = ''
timeout( otime ) {
@socket = TCPsocket.new( addr, port )
}
@closed = false
@ipaddr = @socket.addr[3]
connect otime
D 'opened'
end
def connect( otime )
D "opening connection to #{@addr}..."
timeout( otime ) {
@socket = TCPsocket.new( @addr, @port )
}
end
private :connect
attr :pipe, true
class << self
@ -509,29 +513,31 @@ module Net
end
def inspect
"#<#{type} open=#{!@closed}>"
"#<#{type} #{closed? ? 'closed' : 'opened'}>"
end
def reopen( otime = nil )
unless closed? then
close
@buffer = ''
end
timeout( otime ) {
@socket = TCPsocket.new( @addr, @port )
}
@closed = false
D 'reopening...'
close
connect otime
D 'reopened'
end
attr :socket, true
def close
@socket.close
@closed = true
if @socket then
@socket.close
D 'closed'
else
D 'close call for already closed socket'
end
@socket = nil
@buffer = ''
end
def closed?
@closed
not @socket
end
def address
@ -543,7 +549,8 @@ module Net
attr_reader :port
def ip_address
@ipaddr.dup
@socket or return ''
@socket.addr[3]
end
alias ipaddr ip_address
@ -560,7 +567,7 @@ module Net
CRLF = "\r\n"
def read( len, dest = '', ignerr = false )
D_off "reading #{len} bytes...\n"
D_off "reading #{len} bytes..."
rsize = 0
begin
@ -573,12 +580,12 @@ module Net
raise unless igneof
end
D_on "read #{len} bytes\n"
D_on "read #{len} bytes"
dest
end
def read_all( dest = '' )
D_off "reading all...\n"
D_off 'reading all...'
rsize = 0
begin
@ -590,7 +597,7 @@ module Net
;
end
D_on "read #{rsize} bytes\n"
D_on "read #{rsize} bytes"
dest
end
@ -617,7 +624,7 @@ module Net
end
def read_pendstr( dest )
D_off "reading text...\n"
D_off 'reading text...'
rsize = 0
while (str = readuntil("\r\n")) != ".\r\n" do
@ -626,13 +633,13 @@ module Net
dest << str
end
D_on "read #{rsize} bytes\n"
D_on "read #{rsize} bytes"
dest
end
# private use only (can not handle 'break')
def read_pendlist
D_off "reading list...\n"
D_off 'reading list...'
str = nil
i = 0
@ -642,7 +649,7 @@ module Net
yield str
end
D_on "read #{i} items\n"
D_on "read #{i} items"
end
@ -705,7 +712,7 @@ module Net
end
def write_pendstr( src, block )
D_off "writing text from #{src.type}\n"
D_off "writing text from #{src.type}"
wsize = use_each_crlf_line {
if block then
@ -715,7 +722,7 @@ module Net
end
}
D_on "wrote #{wsize} bytes text\n"
D_on "wrote #{wsize} bytes text"
wsize
end
@ -762,17 +769,17 @@ module Net
beg = 0
buf = @wbuf
while buf.index( /\n|\r\n|\r/, beg ) do
m = $~
m = Regexp.last_match
if m.begin(0) == buf.size - 1 and buf[-1] == ?\r then
# "...\r" : can follow "\n..."
break
end
str = buf[ beg, m.begin(0) - beg ]
str = buf[ beg ... m.begin(0) ]
str.concat "\r\n"
yield str
beg = m.end(0)
end
@wbuf = buf[ beg, buf.size - beg ]
@wbuf = buf[ beg ... buf.size ]
end
end
@ -836,14 +843,19 @@ module Net
def D_off( msg )
@debugout << msg if @debugout
D msg
@savedo, @debugout = @debugout, nil
end
def D_on( msg )
@debugout = @savedo
@savedo = nil
@debugout << msg if @debugout
D msg
end
def D( msg )
@debugout or return
@debugout << msg
@debugout << "\n"
end
end