From a1d1b1516750c1047ceb7010f8f5ca34b358c7e3 Mon Sep 17 00:00:00 2001 From: aamine Date: Wed, 29 Dec 1999 11:14:04 +0000 Subject: Net version 1.1.3 o http.rb rd o Session -> Protocol git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@596 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/net/http.rb | 404 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 225 insertions(+), 179 deletions(-) (limited to 'lib/net/http.rb') diff --git a/lib/net/http.rb b/lib/net/http.rb index a3d271c574..6c1161ee9c 100644 --- a/lib/net/http.rb +++ b/lib/net/http.rb @@ -5,6 +5,9 @@ maintained by Minero Aoki This file is derived from http-access.rb +This library is distributed under the terms of the Ruby license. +You can freely distribute/modify this library. + =end require 'net/session' @@ -17,253 +20,296 @@ class HTTPError < ProtocolError; end class HTTPBadResponse < HTTPError; end -class HTTPSession < Session +=begin - Version = '1.1.2' += HTTP class - session_setvar :port, '80' - session_setvar :command_type, 'Net::HTTPCommand' +== Class Methods +: new( address, port = 80 ) + + create new HTTP object. - def get( path = '/', header = nil, ret = '' ) - confirm_connection - @proto.get edit_path(path), header, ret - end +: port - def head( path = '/', header = nil ) - confirm_connection - @proto.head edit_path(path), header - end + returns HTTP default port, 80 +: command_type - private + returns Command class, HTTPCommand - def confirm_connection - if @socket.closed? then - @socket.reopen - end - end +== Methods + +: get( path, header = nil, ret = '' ) - def do_finish - unless @proto.error_occured or @socket.closed? then - head '/', { 'Connection' => 'Close' } - end - end + get data from "path" on connecting host. + "header" is a Hash like { 'Accept' => '*/*', ... }. + The data will be written to "ret" using "<<" method. + This method returns response header (Hash) and "ret". +: head( path, header = nil ) + + get only header from "path" on connecting host. + "header" is a Hash like { 'Accept' => '*/*', ... }. + This method returns header as a Hash like - def edit_path( path ) - path - end + { 'content-length' => 'Content-Length: 2554', + 'content-type' => 'Content-Type: text/html', + ... } - class << self - def Proxy( addr, port ) - klass = super - klass.module_eval %- - def edit_path( path ) - 'http://' + address + (port == self.port ? '' : ":\#{port}") + path - end - - - klass - end - end +=end -end + class HTTP < Protocol -HTTP = HTTPSession + Version = '1.1.3' + protocol_param :port, '80' + protocol_param :command_type, '::Net::HTTPCommand' -class HTTPCommand < Command - HTTPVersion = '1.1' + def get( path, u_header = nil, ret = '' ) + header = connecting { + @command.get ret, edit_path(path), u_header + } + return header, ret + end - def initialize( sock ) - @http_version = HTTPVersion + def head( path, u_header = nil ) + connecting { + @command.head edit_path(path), u_header + } + end - @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 + private - attr :http_version + def connecting + if @socket.closed? then + @socket.reopen + end + header = yield + @socket.close unless keep_alive? header + + header + end + + def keep_alive?( header ) + if str = header[ 'connection' ] then + if /\Aconnection:\s*keep-alive/i === str then + return true + end + else + if @http_version == '1.1' then + return true + end + end + + false + end - def get( path, u_header = nil, ret = '' ) - header = get_response( - sprintf( 'GET %s HTTP/%s', path, HTTPVersion ), u_header ) - if chunked? header then - clen = read_chunked_body( ret ) - header.delete 'transfer-encoding' - header[ 'content-length' ] = "Content-Length: #{clen}" - else - @socket.read content_length( header ), ret + def do_finish + unless @command.error_occured or @socket.closed? then + head '/', { 'Connection' => 'Close' } + end end - @socket.close unless keep_alive? header - return header, ret - end + def edit_path( path ) + path + end - def head( path, u_header = nil ) - header = get_response( - sprintf( 'HEAD %s HTTP/%s', path, HTTPVersion ), u_header ) - @socket.close unless keep_alive? header + class << self + def Proxy( p_addr, p_port ) + klass = super + klass.module_eval %- + def edit_path( path ) + 'http://' + address + + (@port == #{self.port} ? '' : ':' + @port.to_s) + path + end + - + klass + end + end - header end + HTTPSession = HTTP + + + class HTTPCommand < Command - # def put + HTTPVersion = '1.1' - # def delete + def initialize( sock ) + @http_version = HTTPVersion - # def trace + @in_header = {} + @in_header[ 'Host' ] = sock.addr + @in_header[ 'Connection' ] = 'keep-alive' + @in_header[ 'Accept' ] = '*/*' - # def options + super sock + end - private + attr :http_version + def get( ret, path, u_header = nil ) + header = get_response( + sprintf( 'GET %s HTTP/%s', path, HTTPVersion ), u_header ) + + if chunked? header then + clen = read_chunked_body( ret ) + header.delete 'transfer-encoding' + header[ 'content-length' ] = "Content-Length: #{clen}" + else + @socket.read content_length( header ), ret + end - def do_quit - unless @socket.closed? then - @socket.close + header end - end - def get_response( line, u_header ) - @socket.writeline line - write_header u_header - rep = get_reply - header = read_header - reply_must rep, SuccessCode - header - end + def head( path, u_header = nil ) + get_response sprintf( 'HEAD %s HTTP/%s', path, HTTPVersion ), u_header + end - def get_reply - str = @socket.readline - unless /\AHTTP\/(\d+\.\d+)?\s+(\d\d\d)\s*(.*)\z/i === str then - raise HTTPBadResponse, "wrong status line format: #{str}" + + # def put + + # def delete + + # def trace + + # def options + + + private + + + def do_quit + unless @socket.closed? then + @socket.close + end end - @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" + def get_response( line, u_header ) + @socket.writeline line + write_header u_header + rep = get_reply + header = read_header + reply_must rep, SuccessCode + + header end - unless /\Acontent-length:\s*(\d+)/i === str then - raise HTTPBadResponce, "content-length format error" + + def get_reply + str = @socket.readline + unless /\AHTTP\/(\d+\.\d+)?\s+(\d\d\d)\s*(.*)\z/i === str then + raise HTTPBadResponse, "wrong status line format: #{str}" + end + @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 - $1.to_i - end - def keep_alive?( header ) - if str = header[ 'connection' ] then - if /\Aconnection:\s*keep-alive/i === str then - return true + + def content_length( header ) + unless str = header[ 'content-length' ] then + raise HTTPBadResponce, "content-length not given" end - else - if @http_version == '1.1' then - return true + unless /\Acontent-length:\s*(\d+)/i === str then + raise HTTPBadResponce, "content-length format error" end + $1.to_i end - false - end - - def chunked?( header ) - if str = header[ 'transfer-encoding' ] then - if /\Atransfer-encoding:\s*chunked/i === str then - return true + def chunked?( header ) + if str = header[ 'transfer-encoding' ] then + if /\Atransfer-encoding:\s*chunked/i === str then + return true + end end + + false 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 - def read_header - header = {} - while true do - line = @socket.readline - break if line.empty? - /\A[^:]+/ === line - nm = $& - nm.strip! - nm.downcase! - header[ nm ] = line + header 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 '' + 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 + if tmp = header['Connection'] then + /close/i === tmp + else + false + end end - end - def read_chunked_body( ret ) - line = nil - len = nil - total = 0 + def read_chunked_body( ret ) + line = nil + len = nil + total = 0 - while true do - line = @socket.readline - unless /[0-9a-hA-H]+/ === line then - raise HTTPBadResponce, "chunk size not given" + while true do + line = @socket.readline + unless /[0-9a-hA-H]+/ === line then + raise HTTPBadResponce, "chunk size not given" + end + len = $&.hex + break if len == 0 + @socket.read( len, ret ); total += len + @socket.read 2 # \r\n end - len = $&.hex - break if len == 0 - @socket.read( len, ret ); total += len - @socket.read 2 # \r\n - end - while true do - line = @socket.readline - break if line.empty? + while true do + line = @socket.readline + break if line.empty? + end + + total end - total end -end - end # module Net -- cgit v1.2.3