1999-12-17 10:00:13 -05:00
|
|
|
=begin
|
|
|
|
|
|
|
|
= net/http.rb
|
|
|
|
|
|
|
|
maintained by Minero Aoki <aamine@dp.u-netsurf.ne.jp>
|
2000-03-05 05:25:53 -05:00
|
|
|
This file is derived from "http-access.rb".
|
1999-12-17 10:00:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
This library is distributed under the terms of the Ruby license.
|
|
|
|
You can freely distribute/modify this library.
|
|
|
|
|
1999-12-17 10:00:13 -05:00
|
|
|
=end
|
|
|
|
|
2000-02-21 10:25:37 -05:00
|
|
|
require 'net/protocol'
|
1999-12-17 10:00:13 -05:00
|
|
|
|
|
|
|
|
|
|
|
module Net
|
|
|
|
|
|
|
|
|
|
|
|
class HTTPError < ProtocolError; end
|
|
|
|
class HTTPBadResponse < HTTPError; end
|
|
|
|
|
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
=begin
|
1999-12-17 10:00:13 -05:00
|
|
|
|
2000-03-05 05:25:53 -05:00
|
|
|
= class HTTP
|
1999-12-17 10:00:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
== Class Methods
|
1999-12-17 10:00:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
: new( address, port = 80 )
|
|
|
|
create new HTTP object.
|
1999-12-17 10:00:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
: port
|
|
|
|
returns HTTP default port, 80
|
1999-12-17 10:00:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
: command_type
|
|
|
|
returns Command class, HTTPCommand
|
1999-12-17 10:00:13 -05:00
|
|
|
|
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
== Methods
|
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
: get( path, header = nil, dest = '' )
|
|
|
|
: get( path, header = nil ) {|str| .... }
|
1999-12-29 06:14:04 -05:00
|
|
|
get data from "path" on connecting host.
|
2000-03-26 03:48:15 -05:00
|
|
|
"header" must be a Hash like { 'Accept' => '*/*', ... }.
|
|
|
|
Data is written to "dest" by using "<<" method.
|
|
|
|
This method returns response header (Hash) and "dest".
|
|
|
|
|
|
|
|
If called as iterator, give a part String of entity body.
|
1999-12-22 08:49:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
: 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
|
1999-12-22 08:49:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
{ 'content-length' => 'Content-Length: 2554',
|
|
|
|
'content-type' => 'Content-Type: text/html',
|
|
|
|
... }
|
1999-12-22 08:49:13 -05:00
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
: post( path, data, header = nil, dest = '' )
|
|
|
|
: post( path, data, header = nil ) {|str| .... }
|
|
|
|
post "data"(must be String now) to "path" (and get entity body).
|
|
|
|
"header" must be a Hash like { 'Accept' => '*/*', ... }.
|
|
|
|
Data is written to "dest" by using "<<" method.
|
|
|
|
This method returns response header (Hash) and "dest".
|
|
|
|
|
|
|
|
If called as iterator, give a part String of entity body.
|
|
|
|
|
|
|
|
ATTENTION: entity body could be empty
|
|
|
|
|
|
|
|
: get2( path, header = nil )
|
|
|
|
send GET request for "path".
|
|
|
|
"header" must be a Hash like { 'Accept' => '*/*', ... }.
|
|
|
|
This method returns response header (Hash).
|
|
|
|
|
|
|
|
: get_body( dest = '' )
|
|
|
|
: get_body {|str| .... }
|
|
|
|
gets entity body of forwarded 'get2' or 'post2' methods.
|
|
|
|
Data is written in "dest" by using "<<" method.
|
|
|
|
This method returns "dest".
|
|
|
|
|
|
|
|
If called as iterator, give a part String of entity body.
|
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
=end
|
1999-12-17 10:00:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
class HTTP < Protocol
|
1999-12-17 10:00:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
protocol_param :port, '80'
|
|
|
|
protocol_param :command_type, '::Net::HTTPCommand'
|
1999-12-17 10:00:13 -05:00
|
|
|
|
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
def get( path, u_header = nil, dest = nil, &block )
|
2000-03-26 11:29:02 -05:00
|
|
|
u_header = procheader( u_header )
|
2000-03-26 03:48:15 -05:00
|
|
|
if block then
|
|
|
|
dest = ReadAdapter.new( block )
|
|
|
|
ret = nil
|
|
|
|
else
|
|
|
|
dest = ret = ''
|
|
|
|
end
|
|
|
|
resp = nil
|
|
|
|
connecting( u_header ) {
|
|
|
|
@command.get edit_path(path), u_header
|
|
|
|
resp = @command.get_response
|
|
|
|
@command.try_get_body( resp, dest )
|
1999-12-29 06:14:04 -05:00
|
|
|
}
|
2000-03-05 05:25:53 -05:00
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
return resp['http-header'], ret
|
1999-12-29 06:14:04 -05:00
|
|
|
end
|
1999-12-17 10:00:13 -05:00
|
|
|
|
2000-03-26 11:29:02 -05:00
|
|
|
def get2( path, u_header = nil )
|
|
|
|
u_header = procheader( u_header )
|
2000-03-26 03:48:15 -05:00
|
|
|
only_header( :get, path, u_header )
|
|
|
|
end
|
|
|
|
|
|
|
|
def get_body( dest = '', &block )
|
|
|
|
if block then
|
|
|
|
dest = ReadAdapter.new( block )
|
|
|
|
end
|
|
|
|
@command.try_get_body @response, dest
|
|
|
|
ensure_termination @u_header
|
|
|
|
|
|
|
|
dest
|
|
|
|
end
|
|
|
|
|
2000-03-26 11:29:02 -05:00
|
|
|
def head( path, u_header = nil )
|
|
|
|
u_header = procheader( u_header )
|
|
|
|
header = only_header( :head, path, u_header )
|
2000-03-26 03:48:15 -05:00
|
|
|
ensure_termination u_header
|
2000-03-26 11:29:02 -05:00
|
|
|
header
|
2000-03-26 03:48:15 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def post( path, data, u_header = nil, dest = nil, &block )
|
2000-03-26 11:29:02 -05:00
|
|
|
u_header = procheader( u_header )
|
2000-03-26 03:48:15 -05:00
|
|
|
if block then
|
|
|
|
dest = ReadAdapter.new( block )
|
|
|
|
ret = nil
|
|
|
|
else
|
|
|
|
dest = ret = ''
|
|
|
|
end
|
|
|
|
resp = nil
|
|
|
|
connecting( u_header, true ) {
|
|
|
|
@command.post path, u_header, data
|
|
|
|
resp = @command.get_response
|
|
|
|
@command.try_get_body( resp, dest )
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp['http-header'], ret
|
|
|
|
end
|
|
|
|
|
|
|
|
def post2( path, data, u_header = {} )
|
2000-03-26 11:29:02 -05:00
|
|
|
u_header = procheader( u_header )
|
2000-03-26 03:48:15 -05:00
|
|
|
only_header :post, path, u_header, data
|
|
|
|
end
|
|
|
|
|
|
|
|
# not tested because I could not setup apache (__;;;
|
2000-03-26 11:29:02 -05:00
|
|
|
def put( path, src = nil, u_header = nil, &block )
|
|
|
|
u_header = procheader( u_header )
|
2000-03-26 03:48:15 -05:00
|
|
|
connecting( u_header, true ) {
|
|
|
|
@command.put path, u_header, src, dest
|
1999-12-29 06:14:04 -05:00
|
|
|
}
|
2000-03-05 05:25:53 -05:00
|
|
|
|
|
|
|
header
|
1999-12-29 06:14:04 -05:00
|
|
|
end
|
1999-12-17 10:00:13 -05:00
|
|
|
|
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
private
|
1999-12-17 10:00:13 -05:00
|
|
|
|
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
def only_header( mid, path, u_header, data = nil )
|
2000-03-26 11:29:02 -05:00
|
|
|
@u_header = u_header
|
2000-03-26 03:48:15 -05:00
|
|
|
@response = nil
|
2000-03-26 11:29:02 -05:00
|
|
|
ensure_connection u_header
|
2000-03-26 03:48:15 -05:00
|
|
|
if data then
|
2000-03-26 11:29:02 -05:00
|
|
|
@command.send mid, edit_path(path), u_header, data
|
2000-03-26 03:48:15 -05:00
|
|
|
else
|
2000-03-26 11:29:02 -05:00
|
|
|
@command.send mid, edit_path(path), u_header
|
2000-03-26 03:48:15 -05:00
|
|
|
end
|
|
|
|
@response = @command.get_response
|
|
|
|
@response['http-header']
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2000-03-05 05:25:53 -05:00
|
|
|
# called when connecting
|
|
|
|
def do_finish
|
|
|
|
unless @socket.closed? then
|
2000-03-26 03:48:15 -05:00
|
|
|
begin
|
|
|
|
@command.head '/', { 'Connection' => 'Close' }
|
|
|
|
rescue EOFError
|
|
|
|
end
|
2000-03-05 05:25:53 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
def connecting( u_header, putp = false )
|
|
|
|
ensure_connection u_header
|
|
|
|
yield
|
|
|
|
ensure_termination u_header
|
|
|
|
end
|
2000-03-05 05:25:53 -05:00
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
def ensure_connection( u_header )
|
2000-03-05 05:25:53 -05:00
|
|
|
if not @socket then
|
|
|
|
u_header['Connection'] = 'Close'
|
|
|
|
start
|
|
|
|
elsif @socket.closed? then
|
1999-12-29 06:14:04 -05:00
|
|
|
@socket.reopen
|
|
|
|
end
|
2000-03-26 03:48:15 -05:00
|
|
|
end
|
1999-12-29 06:14:04 -05:00
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
def ensure_termination( u_header )
|
2000-03-26 11:29:02 -05:00
|
|
|
unless keep_alive? u_header and not @socket.closed? then
|
2000-03-05 05:25:53 -05:00
|
|
|
@socket.close
|
|
|
|
end
|
2000-03-26 03:48:15 -05:00
|
|
|
@u_header = @response = nil
|
1999-12-29 06:14:04 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def keep_alive?( header )
|
2000-03-05 05:25:53 -05:00
|
|
|
if str = header['Connection'] then
|
|
|
|
if /\A\s*keep-alive/i === str then
|
1999-12-29 06:14:04 -05:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
else
|
2000-03-05 05:25:53 -05:00
|
|
|
if @command.http_version == '1.1' then
|
1999-12-29 06:14:04 -05:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
false
|
|
|
|
end
|
1999-12-17 10:00:13 -05:00
|
|
|
|
2000-03-05 05:25:53 -05:00
|
|
|
def procheader( h )
|
2000-03-26 11:29:02 -05:00
|
|
|
return( {} ) unless h
|
2000-03-05 05:25:53 -05:00
|
|
|
new = {}
|
|
|
|
h.each do |k,v|
|
|
|
|
arr = k.split('-')
|
|
|
|
arr.each{|i| i.capitalize! }
|
|
|
|
new[ arr.join('-') ] = v
|
1999-12-29 06:14:04 -05:00
|
|
|
end
|
1999-12-20 15:48:49 -05:00
|
|
|
end
|
1999-12-17 10:00:13 -05:00
|
|
|
|
2000-03-05 05:25:53 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
def edit_path( path )
|
|
|
|
path
|
|
|
|
end
|
1999-12-17 10:00:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
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
|
1999-12-17 10:00:13 -05:00
|
|
|
|
|
|
|
end
|
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
HTTPSession = HTTP
|
|
|
|
|
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
class HTTPSuccessCode < SuccessCode; end
|
|
|
|
class HTTPCreatedCode < SuccessCode; end
|
|
|
|
class HTTPAcceptedCode < SuccessCode; end
|
|
|
|
class HTTPNoContentCode < SuccessCode; end
|
|
|
|
class HTTPResetContentCode < SuccessCode; end
|
|
|
|
class HTTPPartialContentCode < SuccessCode; end
|
|
|
|
|
|
|
|
class HTTPMultipleChoiceCode < RetryCode; end
|
|
|
|
class HTTPMovedPermanentlyCode < RetryCode; end
|
|
|
|
class HTTPMovedTemporarilyCode < RetryCode; end
|
|
|
|
class HTTPNotModifiedCode < RetryCode; end
|
|
|
|
class HTTPUseProxyCode < RetryCode; end
|
|
|
|
|
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
class HTTPCommand < Command
|
1999-12-17 10:00:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
HTTPVersion = '1.1'
|
1999-12-17 10:00:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
def initialize( sock )
|
|
|
|
@http_version = HTTPVersion
|
1999-12-17 10:00:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
@in_header = {}
|
|
|
|
@in_header[ 'Host' ] = sock.addr
|
2000-01-21 07:52:24 -05:00
|
|
|
@in_header[ 'Connection' ] = 'Keep-Alive'
|
1999-12-29 06:14:04 -05:00
|
|
|
@in_header[ 'Accept' ] = '*/*'
|
1999-12-17 10:00:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
super sock
|
|
|
|
end
|
1999-12-17 10:00:13 -05:00
|
|
|
|
|
|
|
|
2000-03-05 05:25:53 -05:00
|
|
|
attr_reader :http_version
|
1999-12-17 10:00:13 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
def get( path, u_header )
|
|
|
|
request sprintf('GET %s HTTP/%s', path, HTTPVersion), u_header
|
1999-12-17 10:00:13 -05:00
|
|
|
end
|
2000-03-26 03:48:15 -05:00
|
|
|
|
|
|
|
def head( path, u_header )
|
|
|
|
request sprintf('HEAD %s HTTP/%s', path, HTTPVersion), u_header
|
1999-12-29 06:14:04 -05:00
|
|
|
end
|
1999-12-17 10:00:13 -05:00
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
def post( path, u_header, data )
|
|
|
|
request sprintf('POST %s HTTP/%s', path, HTTPVersion), u_header
|
|
|
|
@socket.write data
|
2000-02-21 10:25:37 -05:00
|
|
|
end
|
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
def put( path, u_header, src )
|
|
|
|
request sprintf('PUT %s HTTP/%s', path, HTTPVersion), u_header
|
|
|
|
@socket.write_bin src
|
2000-02-21 10:25:37 -05:00
|
|
|
end
|
1999-12-29 06:14:04 -05:00
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
# def delete
|
|
|
|
|
|
|
|
# def trace
|
|
|
|
|
|
|
|
# def options
|
|
|
|
|
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
def get_response
|
1999-12-29 06:14:04 -05:00
|
|
|
rep = get_reply
|
2000-03-26 03:48:15 -05:00
|
|
|
rep = get_reply while ContinueCode === rep
|
|
|
|
header = {}
|
|
|
|
while true do
|
|
|
|
line = @socket.readline
|
|
|
|
break if line.empty?
|
|
|
|
nm = /\A[^:]+/.match( line )[0].strip.downcase
|
|
|
|
header[nm] = line
|
|
|
|
end
|
|
|
|
|
|
|
|
rep['http-header'] = header
|
1999-12-29 06:14:04 -05:00
|
|
|
reply_must rep, SuccessCode
|
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
rep
|
|
|
|
end
|
|
|
|
|
|
|
|
def get_body( rep, dest )
|
|
|
|
header = rep['http-header']
|
|
|
|
if chunked? header then
|
|
|
|
read_chunked( dest, header )
|
|
|
|
else
|
|
|
|
if clen = content_length( header ) then
|
|
|
|
@socket.read clen, dest
|
|
|
|
else
|
2000-03-26 11:29:02 -05:00
|
|
|
##### "multipart/byteranges" check should be done here ...
|
|
|
|
|
|
|
|
# now, length is designated by closing socket
|
2000-03-26 03:48:15 -05:00
|
|
|
@socket.read_all dest
|
2000-03-26 11:29:02 -05:00
|
|
|
@socket.close
|
2000-03-26 03:48:15 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def try_get_body( rep, dest )
|
|
|
|
rep = get_reply while ContinueCode === rep
|
|
|
|
return nil unless rep['body-exist']
|
|
|
|
|
|
|
|
get_body rep, dest
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
|
|
|
|
def request( req, u_header )
|
|
|
|
@socket.writeline req
|
|
|
|
if u_header then
|
|
|
|
header = @in_header.dup.update( u_header )
|
|
|
|
else
|
|
|
|
header = @in_header
|
|
|
|
end
|
|
|
|
header.each do |n,v|
|
|
|
|
@socket.writeline n + ': ' + v
|
|
|
|
end
|
|
|
|
@socket.writeline ''
|
1999-12-17 10:00:13 -05:00
|
|
|
end
|
1999-12-29 06:14:04 -05:00
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
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
|
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
be = false
|
1999-12-29 06:14:04 -05:00
|
|
|
klass = case status[0]
|
|
|
|
when ?1 then
|
|
|
|
case status[2]
|
|
|
|
when ?0 then ContinueCode
|
2000-03-26 03:48:15 -05:00
|
|
|
when ?1 then HTTPSuccessCode
|
|
|
|
else UnknownCode
|
|
|
|
end
|
|
|
|
when ?2 then
|
|
|
|
case status[2]
|
|
|
|
when ?0 then be = true; HTTPSuccessCode
|
|
|
|
when ?1 then be = false; HTTPSuccessCode
|
|
|
|
when ?2 then be = true; HTTPSuccessCode
|
|
|
|
when ?3 then be = true; HTTPSuccessCode
|
|
|
|
when ?4 then be = false; HTTPNoContentCode
|
|
|
|
when ?5 then be = false; HTTPResetContentCode
|
|
|
|
when ?6 then be = true; HTTPPartialContentCode
|
|
|
|
else UnknownCode
|
|
|
|
end
|
|
|
|
when ?3 then
|
|
|
|
case status[2]
|
|
|
|
when ?0 then be = true; HTTPMultipleChoiceCode
|
|
|
|
when ?1 then be = true; HTTPMovedPermanentryCode
|
|
|
|
when ?2 then be = true; HTTPMovedTemporarilyCode
|
|
|
|
when ?3 then be = true; HTTPMovedPermanentryCode
|
|
|
|
when ?4 then be = false; HTTPNotModifiedCode
|
|
|
|
when ?5 then be = false; HTTPUseProxyCode
|
1999-12-29 06:14:04 -05:00
|
|
|
else UnknownCode
|
|
|
|
end
|
|
|
|
when ?4 then ServerBusyCode
|
|
|
|
when ?5 then FatalErrorCode
|
2000-03-05 05:25:53 -05:00
|
|
|
else UnknownCode
|
1999-12-29 06:14:04 -05:00
|
|
|
end
|
2000-03-26 03:48:15 -05:00
|
|
|
code = klass.new( status, discrip )
|
|
|
|
code['body-exist'] = be
|
|
|
|
code
|
1999-12-20 15:48:49 -05:00
|
|
|
end
|
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
def read_chunked( ret, header )
|
1999-12-29 06:14:04 -05:00
|
|
|
line = nil
|
|
|
|
len = nil
|
|
|
|
total = 0
|
1999-12-20 15:48:49 -05:00
|
|
|
|
1999-12-29 06:14:04 -05:00
|
|
|
while true do
|
|
|
|
line = @socket.readline
|
|
|
|
unless /[0-9a-hA-H]+/ === line then
|
2000-01-21 07:52:24 -05:00
|
|
|
raise HTTPBadResponse, "chunk size not given"
|
1999-12-29 06:14:04 -05:00
|
|
|
end
|
|
|
|
len = $&.hex
|
|
|
|
break if len == 0
|
|
|
|
@socket.read( len, ret ); total += len
|
|
|
|
@socket.read 2 # \r\n
|
1999-12-20 15:48:49 -05:00
|
|
|
end
|
1999-12-29 06:14:04 -05:00
|
|
|
while true do
|
|
|
|
line = @socket.readline
|
|
|
|
break if line.empty?
|
|
|
|
end
|
|
|
|
|
2000-03-26 03:48:15 -05:00
|
|
|
header.delete 'transfer-encoding'
|
|
|
|
header[ 'content-length' ] = "Content-Length: #{total}"
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
def content_length( header )
|
|
|
|
unless str = header[ 'content-length' ] then
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
unless /\Acontent-length:\s*(\d+)/i === str then
|
|
|
|
raise HTTPBadResponse, "content-length format error"
|
|
|
|
end
|
|
|
|
$1.to_i
|
|
|
|
end
|
|
|
|
|
|
|
|
def chunked?( header )
|
|
|
|
if str = header[ 'transfer-encoding' ] then
|
|
|
|
if /\Atransfer-encoding:\s*chunked/i === str then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
false
|
1999-12-20 15:48:49 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
1999-12-17 10:00:13 -05:00
|
|
|
|
|
|
|
end # module Net
|