From acce0b7ec4f5b6682b94e458675020263068d306 Mon Sep 17 00:00:00 2001 From: aamine Date: Thu, 22 Feb 2001 23:23:57 +0000 Subject: aamine * 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 --- lib/net/http.rb | 285 +++++++++++++++++++++++++++++++--------------------- lib/net/protocol.rb | 80 ++++++++------- 2 files changed, 219 insertions(+), 146 deletions(-) (limited to 'lib/net') diff --git a/lib/net/http.rb b/lib/net/http.rb index 402987ca9c..75021da353 100644 --- a/lib/net/http.rb +++ b/lib/net/http.rb @@ -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,66 +585,167 @@ module Net net_private { - class HTTPRequest + module HTTPHeader - def initialize( path, uhead = nil ) - @path = path - @u_header = tmp = {} - return unless uhead - uhead.each do |k,v| - key = canonical(k) - if tmp.key? key then - $stderr.puts "WARNING: duplicated HTTP header: #{k}" if $VERBOSE - end - tmp[ key ] = v.strip - end - - @socket = nil - @response = nil + def size + @header.size end - attr_reader :path - attr_reader :response - - def inspect - "\#<#{type}>" - end + alias length size def []( key ) - @u_header[ canonical key ] + @header[ key.downcase ] end def []=( key, val ) - @u_header[ canonical key ] = val + @header[ key.downcase ] = val end - def key?( key ) - @u_header.key? canonical(key) + def each( &block ) + @header.each( &block ) end - def delete( key ) - @u_header.delete canonical(key) + def each_key( &block ) + @header.each_key( &block ) end - def each( &block ) - @u_header.each( &block ) + def each_value( &block ) + @header.each_value( &block ) end - def each_key( &block ) - @u_header.each_key( &block ) + def delete( key ) + @header.delete key.downcase end - def each_value( &block ) - @u_header.each_value( &block ) + def key?( key ) + @header.key? key.downcase end + def to_hash + @header.dup + end - private + 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 = %ri.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 + @header = tmp = {} + return unless uhead + uhead.each do |k,v| + key = k.downcase + if tmp.key? key then + $stderr.puts "WARNING: duplicated HTTP header: #{k}" if $VERBOSE + end + tmp[ key ] = v.strip + end + + @socket = nil + @response = nil + end + + attr_reader :path + attr_reader :response + + def inspect + "\#<#{type}>" + end + + + private + # # 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.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 diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb index f936e5c6d6..2ebdcb9046 100644 --- a/lib/net/protocol.rb +++ b/lib/net/protocol.rb @@ -490,17 +490,21 @@ module Net @debugout = dout - @closed = true - @ipaddr = '' + @socket = nil @sending = '' @buffer = '' + connect otime + D 'opened' + end + + def connect( otime ) + D "opening connection to #{@addr}..." timeout( otime ) { - @socket = TCPsocket.new( addr, port ) + @socket = TCPsocket.new( @addr, @port ) } - @closed = false - @ipaddr = @socket.addr[3] end + private :connect attr :pipe, true @@ -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 -- cgit v1.2.3