* lib/net/http.rb: unify coding style.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3070 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
aamine 2002-11-21 11:13:17 +00:00
parent 4a66fdcad3
commit 15911a95bf
2 changed files with 226 additions and 221 deletions

View File

@ -1,3 +1,7 @@
Thu Nov 21 20:17:08 2002 Minero Aoki <aamine@loveruby.net>
* lib/net/http.rb: unify coding style.
Thu Nov 21 20:04:06 2002 Minero Aoki <aamine@loveruby.net> Thu Nov 21 20:04:06 2002 Minero Aoki <aamine@loveruby.net>
* lib/net/http.rb: should not overwrite Host: header. * lib/net/http.rb: should not overwrite Host: header.

View File

@ -4,31 +4,33 @@
Copyright (c) 1999-2002 Yukihiro Matsumoto Copyright (c) 1999-2002 Yukihiro Matsumoto
written & maintained by Minero Aoki <aamine@loveruby.net> written & maintained by Minero Aoki <aamine@loveruby.net>.
This file is derived from "http-access.rb". This file is derived from "http-access.rb".
This program is free software. You can re-distribute and/or This program is free software. You can re-distribute and/or
modify this program under the same terms as Ruby itself, modify this program under the same terms of ruby itself ---
Ruby Distribute License or GNU General Public License. Ruby Distribute License or GNU General Public License.
NOTE: You can find Japanese version of this document in NOTE: You can find Japanese version of this document here:
the doc/net directory of the standard ruby interpreter package. ((<URL:http://www.ruby-lang.org/ja/man-1.6/?cmd=view;name=net%2Fhttp.rb>))
$Id$ $Id$
== What is this module? == What Is This Library?
This module provide your program the functions to access WWW This library provides your program functions to access WWW
documents via HTTP, Hyper Text Transfer Protocol version 1.1. documents via HTTP, Hyper Text Transfer Protocol version 1.1.
For details of HTTP, refer [RFC2616] For details of HTTP, refer [RFC2616]
((<URL:http://www.ietf.org/rfc/rfc2616.txt>)). ((<URL:http://www.ietf.org/rfc/rfc2616.txt>)).
== Examples == Examples
=== Getting Document From Server === Getting Document From WWW Server
(formal version)
require 'net/http' require 'net/http'
Net::HTTP.start( 'some.www.server', 80 ) {|http| Net::HTTP.start('www.example.com', 80) {|http|
response = http.get('/index.html') response = http.get('/index.html')
puts response.body puts response.body
} }
@ -36,52 +38,56 @@ For details of HTTP, refer [RFC2616]
(shorter version) (shorter version)
require 'net/http' require 'net/http'
Net::HTTP.get_print 'some.www.server', '/index.html' Net::HTTP.get_print 'www.example.com', '/index.html'
# or
or
require 'net/http'
require 'uri'
Net::HTTP.get_print URI.parse('http://www.example.com/index.html') Net::HTTP.get_print URI.parse('http://www.example.com/index.html')
=== Posting Form Data === Posting Form Data
require 'net/http' require 'net/http'
Net::HTTP.start( 'some.www.server', 80 ) {|http| Net::HTTP.start('some.www.server', 80) {|http|
response = http.post('/cgi-bin/any.rhtml', response = http.post('/cgi-bin/search.rb', 'query=ruby')
'querytype=subject&target=ruby')
} }
=== Accessing via Proxy === Accessing via Proxy
Net::HTTP.Proxy() creates http proxy class. It has same Net::HTTP.Proxy creates http proxy class. It has same
methods of Net::HTTP but its instances always connect to methods of Net::HTTP but its instances always connect to
proxy, instead of given host. proxy, instead of given host.
require 'net/http' require 'net/http'
$proxy_addr = 'your.proxy.addr' proxy_addr = 'your.proxy.host'
$proxy_port = 8080 proxy_port = 8080
: :
Net::HTTP::Proxy($proxy_addr, $proxy_port).start('some.www.server') {|http| Net::HTTP::Proxy(proxy_addr, proxy_port).start('www.example.com') {|http|
# always connect to your.proxy.addr:8080 # always connect to your.proxy.addr:8080
: :
} }
Since Net::HTTP.Proxy() returns Net::HTTP itself when $proxy_addr is nil, Since Net::HTTP.Proxy returns Net::HTTP itself when proxy_addr is nil,
there's no need to change code if there's proxy or not. there's no need to change code if there's proxy or not.
There are two additional parameters in Net::HTTP.Proxy() which allow to specify There are two additional parameters in Net::HTTP.Proxy which allow to
proxy user name and password: specify proxy user name and password:
Net::HTTP::Proxy(proxy_addr, proxy_port, proxy_name = nil, proxy_pass = nil) Net::HTTP::Proxy(proxy_addr, proxy_port, proxy_user = nil, proxy_pass = nil)
You may use them to work with authorization-enabled proxies: You may use them to work with authorization-enabled proxies:
require 'net/http' require 'net/http'
require 'uri' require 'uri'
proxy_info = URI.parse(ENV['http_proxy']) proxy_host = 'your.proxy.host'
proxy_port = 8080
proxy_name, proxy_pass = proxy_info.userinfo.split(":") if proxy_info.userinfo uri = URI.parse(ENV['http_proxy'])
proxy_user, proxy_pass = uri.userinfo.split(/:/) if uri.userinfo
Net::HTTP::Proxy($proxy_addr, $proxy_port, proxy_name, proxy_pass).start('some.www.server') {|http| Net::HTTP::Proxy(proxy_host, proxy_port,
proxy_user, proxy_pass).start('www.example.com') {|http|
# always connect to your.proxy.addr:8080 using specified username and password # always connect to your.proxy.addr:8080 using specified username and password
: :
} }
@ -90,18 +96,22 @@ You may use them to work with authorization-enabled proxies:
=== Following Redirection === Following Redirection
require 'net/http' require 'net/http'
require 'uri'
def fetch( uri_str, limit = 10 )
# You should choose better exception.
raise ArgumentError, 'http redirect too deep' if limit == 0
def read_uri( uri_str )
response = Net::HTTP.get_response(URI.parse(uri_str)) response = Net::HTTP.get_response(URI.parse(uri_str))
case response case response
when Net::HTTPSuccess then response when Net::HTTPSuccess then response
when Net::HTTPRedirection then read_uri(response['location']) when Net::HTTPRedirection then fetch(response['location'], limit - 1)
else else
response.error! response.error!
end end
end end
print read_uri('http://www.ruby-lang.org') print fetch('http://www.ruby-lang.org')
Net::HTTPSuccess and Net::HTTPRedirection is a HTTPResponse class. Net::HTTPSuccess and Net::HTTPRedirection is a HTTPResponse class.
All HTTPResponse objects belong to its own response class which All HTTPResponse objects belong to its own response class which
@ -112,9 +122,9 @@ see section "HTTP Response Classes".
require 'net/http' require 'net/http'
req = Net::HTTP::Get.new('/need-auth.cgi') Net::HTTP.start('www.example.com') {|http|
req.basic_auth 'account', 'password' req = Net::HTTP::Get.new('/secret-page.html')
Net::HTTP.start( 'auth.some.domain' ) {|http| req.basic_auth 'account', 'password'
response = http.request(req) response = http.request(req)
print response.body print response.body
} }
@ -193,7 +203,7 @@ allows you to use 1.2 features again.
Net::HTTP.version_1_2 Net::HTTP.version_1_2
Net::HTTP.start {|http3| ...(http3 has 1.2 features)... } Net::HTTP.start {|http3| ...(http3 has 1.2 features)... }
This function is not thread-safe. This function is not multithread-safe.
== class Net::HTTP == class Net::HTTP
@ -202,10 +212,11 @@ This function is not thread-safe.
: new( address, port = 80, proxy_addr = nil, proxy_port = nil ) : new( address, port = 80, proxy_addr = nil, proxy_port = nil )
creates a new Net::HTTP object. creates a new Net::HTTP object.
If proxy_addr is given, creates an Net::HTTP object with proxy support. If proxy_addr is given, creates an Net::HTTP object with proxy support.
This method does not open TCP connection.
: start( address, port = 80, proxy_addr = nil, proxy_port = nil ) : start( address, port = 80, proxy_addr = nil, proxy_port = nil )
creates a new Net::HTTP object and returns it creates a new Net::HTTP object and returns it
with opening HTTP session. with opening TCP connection and HTTP session.
: start( address, port = 80, proxy_addr = nil, proxy_port = nil ) {|http| .... } : start( address, port = 80, proxy_addr = nil, proxy_port = nil ) {|http| .... }
creates a new Net::HTTP object and gives it to the block. creates a new Net::HTTP object and gives it to the block.
@ -214,14 +225,14 @@ This function is not thread-safe.
This method returns the return value of the block. This method returns the return value of the block.
: get_print( uri ) : get_print( uri )
: get_print( address, path, port = 80 ) : get_print( host, path, port = 80 )
gets entity body from the target and output it to stdout. gets entity body from the target and outputs it to the stdout.
Net::HTTP.get_print URI.parse('http://www.example.com') Net::HTTP.get_print URI.parse('http://www.example.com')
: get( uri ) : get( uri )
: get( address, path, port = 80 ) : get( host, path, port = 80 )
send GET request to the target and get a response. send GET request to the target and gets a response.
This method returns a String. This method returns a String.
print Net::HTTP.get(URI.parse('http://www.example.com')) print Net::HTTP.get(URI.parse('http://www.example.com'))
@ -236,44 +247,44 @@ This function is not thread-safe.
: Proxy( address, port = 80, username = nil, password = nil ) : Proxy( address, port = 80, username = nil, password = nil )
creates a HTTP proxy class. creates a HTTP proxy class.
Arguments are address/port of proxy host and username/password if authorization Arguments are address/port of proxy host and username/password
on proxy server is required. if authorization on proxy server is required.
You can replace HTTP class with created proxy class. You can replace the HTTP class with created proxy class.
If ADDRESS is nil, this method returns self (Net::HTTP). If ADDRESS is nil, this method returns self (Net::HTTP).
# example # Example
proxy_class = Net::HTTP::Proxy( 'proxy.foo.org', 8080 ) proxy_class = Net::HTTP::Proxy('proxy.example.com', 8080)
: :
proxy_class.start( 'www.ruby-lang.org' ) {|http| proxy_class.start('www.ruby-lang.org') {|http|
# connecting proxy.foo.org:8080 # connecting proxy.foo.org:8080
: :
} }
: proxy_class? : proxy_class?
If self is HTTP, false. return true if self is a class which was created by HTTP::Proxy.
If self is a class which was created by HTTP::Proxy(), true.
: port : port
default HTTP port (80). the default HTTP port number (80).
=== Instance Methods === Instance Methods
: start : start
: start {|http| .... } : start {|http| .... }
opens HTTP session. opens TCP connection and HTTP session.
When this method is called with block, gives a HTTP object When this method is called with block, gives a HTTP object
to the block and closes the HTTP session after block call finished. to the block and closes the TCP connection / HTTP session
after the block executed.
: started? : started?
returns true if HTTP session is started. returns true if HTTP session is started.
: address : address
the address to connect The host name to connect.
: port : port
the port number to connect The port number to connect.
: open_timeout : open_timeout
: open_timeout=(n) : open_timeout=(n)
@ -288,7 +299,7 @@ This function is not thread-safe.
it raises TimeoutError exception. it raises TimeoutError exception.
: finish : finish
finishes HTTP session. finishes HTTP session and closes TCP connection.
If HTTP session had not started, raises an IOError. If HTTP session had not started, raises an IOError.
: proxy? : proxy?
@ -301,10 +312,10 @@ This function is not thread-safe.
port number of proxy host. If self does not use a proxy, nil. port number of proxy host. If self does not use a proxy, nil.
: proxy_name : proxy_name
user name for accessing proxy. If self does not use a proxy, nil user name for accessing proxy. If self does not use a proxy, nil.
: proxy_pass : proxy_pass
user password for accessing proxy. If self does not use a proxy, nil user password for accessing proxy. If self does not use a proxy, nil.
: get( path, header = nil ) : get( path, header = nil )
: get( path, header = nil ) {|str| .... } : get( path, header = nil ) {|str| .... }
@ -325,18 +336,14 @@ This function is not thread-safe.
In version 1.2, this method never raises exception. In version 1.2, this method never raises exception.
# version 1.1 (bundled with Ruby 1.6) # version 1.1 (bundled with Ruby 1.6)
response, body = http.get( '/index.html' ) response, body = http.get('/index.html')
# version 1.2 (bundled with Ruby 1.7 or later) # version 1.2 (bundled with Ruby 1.7 or later)
response = http.get( '/index.html' ) response = http.get('/index.html')
# compatible in both version
response , = http.get( '/index.html' )
response.body
# using block # using block
File.open( 'save.txt', 'w' ) {|f| File.open('result.txt', 'w') {|f|
http.get( '/~foo/', nil ) do |str| http.get('/~foo/') do |str|
f.write str f.write str
end end
} }
@ -353,14 +360,14 @@ This function is not thread-safe.
In version 1.2, this method never raises exception. In version 1.2, this method never raises exception.
response = nil response = nil
Net::HTTP.start( 'some.www.server', 80 ) {|http| Net::HTTP.start('some.www.server', 80) {|http|
response = http.head( '/index.html' ) response = http.head('/index.html')
} }
p response['content-type'] p response['content-type']
: post( path, data, header = nil ) : post( path, data, header = nil )
: post( path, data, header = nil ) {|str| .... } : post( path, data, header = nil ) {|str| .... }
posts DATA (must be String) to PATH. HEADER must be a Hash posts DATA (must be a String) to PATH. HEADER must be a Hash
like { 'Accept' => '*/*', ... }. like { 'Accept' => '*/*', ... }.
In version 1.1, this method returns a pair of objects, a In version 1.1, this method returns a pair of objects, a
@ -375,38 +382,35 @@ This function is not thread-safe.
In version 1.2, this method never raises exception. In version 1.2, this method never raises exception.
# version 1.1 # version 1.1
response, body = http.post( '/cgi-bin/search.rb', 'query=subject&target=ruby' ) response, body = http.post('/cgi-bin/search.rb', 'query=foo')
# version 1.2 # version 1.2
response = http.post( '/cgi-bin/search.rb', 'query=subject&target=ruby' ) response = http.post('/cgi-bin/search.rb', 'query=foo')
# compatible in both version
response , = http.post( '/cgi-bin/search.rb', 'query=subject&target=ruby' )
# using block # using block
File.open( 'save.html', 'w' ) {|f| File.open('result.txt', 'w') {|f|
http.post( '/cgi-bin/search.rb', http.post('/cgi-bin/search.rb', 'query=foo') do |str|
'query=subject&target=ruby' ) do |str|
f.write str f.write str
end end
} }
: request_get( path, header = nil ) : request_get( path, header = nil )
: request_get( path, header = nil ) {|response| .... } : request_get( path, header = nil ) {|response| .... }
gets entity from PATH. This method returns a HTTPResponse object. sends GET request to the PATH and get a response,
as a HTTPResponse object.
When called with block, keep connection while block is executed When called with block, gives a HTTPResponse object to the block
and gives a HTTPResponse object to the block. and close the TCP connection after the block is executed.
This method never raises Net::* exceptions. This method never raises Net::* exceptions.
# example response = http.request_get('/index.html')
response = http.request_get( '/index.html' ) # The entity body is already read here.
p response['content-type'] p response['content-type']
puts response.body # body is already read puts response.body
# using block # using block
http.request_get( '/index.html' ) {|response| http.request_get('/index.html') {|response|
p response['content-type'] p response['content-type']
response.read_body do |str| # read body now response.read_body do |str| # read body now
print str print str
@ -415,7 +419,8 @@ This function is not thread-safe.
: request_post( path, data, header = nil ) : request_post( path, data, header = nil )
: request_post( path, data, header = nil ) {|response| .... } : request_post( path, data, header = nil ) {|response| .... }
posts data to PATH. This method returns a HTTPResponse object. sends POST request to the PATH and get a response,
as a HTTPResponse object.
When called with block, gives a HTTPResponse object to the block When called with block, gives a HTTPResponse object to the block
before reading entity body, with keeping connection. before reading entity body, with keeping connection.
@ -423,12 +428,12 @@ This function is not thread-safe.
This method never raises Net::* exceptions. This method never raises Net::* exceptions.
# example # example
response = http.post2( '/cgi-bin/nice.rb', 'datadatadata...' ) response = http.request_post('/cgi-bin/nice.rb', 'datadatadata...')
p response.status p response.status
puts response.body # body is already read puts response.body # body is already read
# using block # using block
http.post2( '/cgi-bin/nice.rb', 'datadatadata...' ) {|response| http.request_post('/cgi-bin/nice.rb', 'datadatadata...') {|response|
p response.status p response.status
p response['content-type'] p response['content-type']
response.read_body do |str| # read body now response.read_body do |str| # read body now
@ -436,10 +441,10 @@ This function is not thread-safe.
end end
} }
: request( request [, data] ) : request( request, data = nil )
: request( request [, data] ) {|response| .... } : request( request, data = nil ) {|response| .... }
sends a HTTPRequest object REQUEST to the HTTP server. sends a HTTPRequest object REQUEST to the HTTP server.
This method also writes DATA string if REQUEST is a post/put request. This method also sends DATA string if REQUEST is a post/put request.
Giving DATA for get/head request causes ArgumentError. Giving DATA for get/head request causes ArgumentError.
If called with block, this method passes a HTTPResponse object to If called with block, this method passes a HTTPResponse object to
@ -459,18 +464,26 @@ You MUST use its subclass, Net::HTTP::Get, Post, Head.
=== Instance Methods === Instance Methods
: self[ key ] : self[key]
returns the header field corresponding to the case-insensitive key. returns the header field corresponding to the case-insensitive key.
For example, a key of "Content-Type" might return "text/html" For example, a key of "Content-Type" might return "text/html"
: self[ key ] = val : self[key] = val
sets the header field corresponding to the case-insensitive key. sets the header field corresponding to the case-insensitive key.
: fetch( key, [, default] )
: fetch( key ) {|key| .... }
returns the header field corresponding to the case-insensitive key.
returns the default value if there's no header field named key.
: each {|name, val| .... } : each {|name, val| .... }
iterates for each field name and value pair. iterates for each field name and value pair.
: basic_auth( account, password ) : basic_auth( account, password )
set Authorization: header for basic auth. set Authorization: header for "Basic" authorization.
: proxy_basic_auth( account, password )
set Proxy-Authorization: header for "Basic" authorization.
: range : range
returns a Range object which represents Range: header field. returns a Range object which represents Range: header field.
@ -493,18 +506,18 @@ All arguments named KEY is case-insensitive.
=== Instance Methods === Instance Methods
: self[ key ] : self[key]
returns the header field corresponding to the case-insensitive key. returns the header field corresponding to the case-insensitive key.
For example, a key of "Content-Type" might return "text/html". For example, a key of "Content-Type" might return "text/html".
A key of "Content-Length" might do "2045". A key of "Content-Length" might do "2045".
More than one fields which has same names are joined with ','. More than one fields which has same names are joined with ','.
: self[ key ] = val : self[key] = val
sets the header field corresponding to the case-insensitive key. sets the header field corresponding to the case-insensitive key.
: fetch( key [,default] ) : fetch( key, [, default] )
: fetch( key ) {|key| .... }
returns the header field corresponding to the case-insensitive key. returns the header field corresponding to the case-insensitive key.
returns the default value if there's no header field named key. returns the default value if there's no header field named key.
@ -602,7 +615,7 @@ module Net
end end
def HTTP.get_response( arg1, arg2 = nil, arg3 = nil ) def HTTP.get_response( arg1, arg2 = nil, arg3 = nil )
if arg2 then if arg2
get_by_path(arg1, arg2, arg3) get_by_path(arg1, arg2, arg3)
else else
get_by_uri(arg1) get_by_uri(arg1)
@ -610,7 +623,7 @@ module Net
end end
def HTTP.get_by_path( addr, path, port = nil ) def HTTP.get_by_path( addr, path, port = nil )
new( addr, port || HTTP.default_port ).start {|http| new(addr, port || HTTP.default_port).start {|http|
return http.request(Get.new(path)) return http.request(Get.new(path))
} }
end end
@ -634,14 +647,14 @@ module Net
protocol_param :socket_type, '::Net::InternetMessageIO' protocol_param :socket_type, '::Net::InternetMessageIO'
class << HTTP class << HTTP
def start( address, port = nil, p_addr = nil, p_port = nil, p_name = nil, p_pass = nil, &block ) def start( address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil, &block )
new( address, port, p_addr, p_port, p_name, p_pass ).start( &block ) new(address, port, p_addr, p_port, p_user, p_pass).start(&block)
end end
alias newobj new alias newobj new
def new( address, port = nil, p_addr = nil, p_port = nil, p_name = nil, p_pass = nil ) def new( address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil )
obj = Proxy(p_addr, p_port, p_name, p_pass ).newobj(address, port) obj = Proxy(p_addr, p_port, p_user, p_pass).newobj(address, port)
setimplversion obj setimplversion obj
obj obj
end end
@ -677,13 +690,12 @@ module Net
@is_proxy_class = false @is_proxy_class = false
@proxy_addr = nil @proxy_addr = nil
@proxy_port = nil @proxy_port = nil
@proxy_name = nil @proxy_user = nil
@proxy_pass = nil @proxy_pass = nil
def HTTP.Proxy( p_addr, p_port = nil, p_name = nil, p_pass = nil ) def HTTP.Proxy( p_addr, p_port = nil, p_user = nil, p_pass = nil )
p_addr or return self return self unless p_addr
p_port ||= port()
delta = ProxyDelta delta = ProxyDelta
proxyclass = Class.new(self) proxyclass = Class.new(self)
proxyclass.module_eval { proxyclass.module_eval {
@ -691,9 +703,9 @@ module Net
# with proxy # with proxy
@is_proxy_class = true @is_proxy_class = true
@proxy_address = p_addr @proxy_address = p_addr
@proxy_port = p_port @proxy_port = p_port || default_port()
@proxy_name = p_name @proxy_user = p_user
@proxy_pass = p_pass @proxy_pass = p_pass
} }
proxyclass proxyclass
end end
@ -705,7 +717,7 @@ module Net
attr_reader :proxy_address attr_reader :proxy_address
attr_reader :proxy_port attr_reader :proxy_port
attr_reader :proxy_name attr_reader :proxy_user
attr_reader :proxy_pass attr_reader :proxy_pass
end end
@ -721,12 +733,20 @@ module Net
self.class.proxy_port self.class.proxy_port
end end
def proxy_user
self.class.proxy_user
end
def proxy_pass
self.class.proxy_pass
end
alias proxyaddr proxy_address alias proxyaddr proxy_address
alias proxyport proxy_port alias proxyport proxy_port
private private
# no proxy # without proxy
def conn_address def conn_address
address address
@ -735,16 +755,10 @@ module Net
def conn_port def conn_port
port port
end end
# Empty, void
def authorization(header)
return header
end
def edit_path( path ) def edit_path( path )
path path
end end
module ProxyDelta module ProxyDelta
private private
@ -752,24 +766,16 @@ module Net
# with proxy # with proxy
def conn_address def conn_address
proxy_address proxy_address()
end end
def conn_port def conn_port
proxy_port proxy_port()
end end
def edit_path( path ) def edit_path( path )
'http://' + addr_port() + path 'http://' + addr_port() + path
end end
def authorization(header)
if self.class.proxy_name then
header = Hash.new unless header
header['Proxy-Authorization'] = "Basic " + ["#{self.class.proxy_name}:#{self.class.proxy_pass}"].pack('m').strip
end
return header
end
end end
@ -781,11 +787,11 @@ module Net
def get( path, initheader = nil, dest = nil, &block ) def get( path, initheader = nil, dest = nil, &block )
res = nil res = nil
initheader = authorization(initheader) request(Get.new(path, initheader)) {|r|
request( Get.new(path,initheader) ) {|res| r.read_body dest, &block
res.read_body dest, &block res = r
} }
unless @newimpl then unless @newimpl
res.value res.value
return res, res.body return res, res.body
end end
@ -794,19 +800,18 @@ module Net
end end
def head( path, initheader = nil ) def head( path, initheader = nil )
initheader = authorization(initheader) res = request(Head.new(path, initheader))
res = request( Head.new(path,initheader) )
@newimpl or res.value @newimpl or res.value
res res
end end
def post( path, data, initheader = nil, dest = nil, &block ) def post( path, data, initheader = nil, dest = nil, &block )
res = nil res = nil
initheader = authorization(initheader) request(Post.new(path, initheader), data) {|r|
request( Post.new(path,initheader), data ) {|res| r.read_body dest, &block
res.read_body dest, &block res = r
} }
unless @newimpl then unless @newimpl
res.value res.value
return res, res.body return res, res.body
end end
@ -815,31 +820,26 @@ module Net
end end
def put( path, data, initheader = nil ) def put( path, data, initheader = nil )
initheader = authorization(initheader) res = request(Put.new(path, initheader), data)
res = request( Put.new(path,initheader), data )
@newimpl or res.value @newimpl or res.value
res res
end end
def request_get( path, initheader = nil, &block ) def request_get( path, initheader = nil, &block )
initheader = authorization(initheader) request Get.new(path, initheader), &block
request Get.new(path,initheader), &block
end end
def request_head( path, initheader = nil, &block ) def request_head( path, initheader = nil, &block )
initheader = authorization(initheader) request Head.new(path, initheader), &block
request Head.new(path,initheader), &block
end end
def request_post( path, data, initheader = nil, &block ) def request_post( path, data, initheader = nil, &block )
initheader = authorization(initheader) request Post.new(path, initheader), data, &block
request Post.new(path,initheader), data, &block
end end
def request_put( path, data, initheader = nil, &block ) def request_put( path, data, initheader = nil, &block )
initheader = authorization(initheader) request Put.new(path, initheader), data, &block
request Put.new(path,initheader), data, &block
end end
alias get2 request_get alias get2 request_get
@ -849,20 +849,21 @@ module Net
def send_request( name, path, body = nil, header = nil ) def send_request( name, path, body = nil, header = nil )
header = authorization(header) r = HTTPGenericRequest.new(name,(body ? true : false),true,path,header)
r = HTTPGenericRequest.new( name, (body ? true : false), true,
path, header )
request r, body request r, body
end end
def request( req, body = nil, &block ) def request( req, body = nil, &block )
unless started? then unless started?
start { start {
req['connection'] = 'close' req['connection'] = 'close'
return request(req, body, &block) return request(req, body, &block)
} }
end end
if proxy_user()
req.proxy_basic_auth proxy_user(), proxy_pass()
end
begin_transport req begin_transport req
req.exec @socket, @curr_http_version, edit_path(req.path), body req.exec @socket, @curr_http_version, edit_path(req.path), body
@ -880,27 +881,27 @@ module Net
private private
def begin_transport( req ) def begin_transport( req )
if @socket.closed? then if @socket.closed?
reconn_socket reconn_socket
end end
if @seems_1_0_server then if @seems_1_0_server
req['connection'] = 'close' req['connection'] = 'close'
end end
if not req.response_body_permitted? and @close_on_empty_response then if not req.response_body_permitted? and @close_on_empty_response
req['connection'] = 'close' req['connection'] = 'close'
end end
req['host'] ||= addr_port() req['host'] = addr_port()
end end
def end_transport( req, res ) def end_transport( req, res )
@curr_http_version = res.http_version @curr_http_version = res.http_version
if not res.body and @close_on_empty_response then if not res.body and @close_on_empty_response
D 'Conn close' D 'Conn close'
@socket.close @socket.close
elsif keep_alive? req, res then elsif keep_alive? req, res
D 'Conn keep-alive' D 'Conn keep-alive'
if @socket.closed? then if @socket.closed?
D 'Conn (but seems 1.0 server)' D 'Conn (but seems 1.0 server)'
@seems_1_0_server = true @seems_1_0_server = true
end end
@ -935,7 +936,7 @@ module Net
end end
def D( msg ) def D( msg )
if @debug_output then if @debug_output
@debug_output << msg @debug_output << msg
@debug_output << "\n" @debug_output << "\n"
end end
@ -959,37 +960,37 @@ module Net
alias length size alias length size
def []( key ) def []( key )
@header[ key.downcase ] @header[key.downcase]
end end
def []=( key, val ) def []=( key, val )
@header[ key.downcase ] = val @header[key.downcase] = val
end
def fetch( key, *args, &block )
@header.fetch(key.downcase, *args, &block)
end end
def each_header( &block ) def each_header( &block )
@header.each( &block ) @header.each(&block)
end end
alias each each_header alias each each_header
def each_key( &block ) def each_key( &block )
@header.each_key( &block ) @header.each_key(&block)
end end
def each_value( &block ) def each_value( &block )
@header.each_value( &block ) @header.each_value(&block)
end end
def delete( key ) def delete( key )
@header.delete key.downcase @header.delete(key.downcase)
end
def fetch(*args)
@header.fetch(*args)
end end
def key?( key ) def key?( key )
@header.key? key.downcase @header.key?(key.downcase)
end end
def to_hash def to_hash
@ -1003,12 +1004,12 @@ module Net
end end
def canonical( k ) def canonical( k )
k.split('-').collect {|i| i.capitalize }.join('-') k.split(/-/).map {|i| i.capitalize }.join('-')
end end
def range def range
s = @header['range'] or return nil s = @header['range'] or return nil
s.split(',').collect {|spec| s.split(/,/).map {|spec|
m = /bytes\s*=\s*(\d+)?\s*-\s*(\d+)?/i.match(spec) or m = /bytes\s*=\s*(\d+)?\s*-\s*(\d+)?/i.match(spec) or
raise HTTPHeaderSyntaxError, "wrong Range: #{spec}" raise HTTPHeaderSyntaxError, "wrong Range: #{spec}"
d1 = m[1].to_i d1 = m[1].to_i
@ -1031,11 +1032,11 @@ module Net
when Range when Range
first = r.first first = r.first
last = r.last last = r.last
if r.exclude_end? then if r.exclude_end?
last -= 1 last -= 1
end end
if last == -1 then if last == -1
s = first > 0 ? "#{first}-" : "-#{-first}" s = first > 0 ? "#{first}-" : "-#{-first}"
else else
first >= 0 or raise HTTPHeaderSyntaxError, 'range.first is negative' first >= 0 or raise HTTPHeaderSyntaxError, 'range.first is negative'
@ -1077,10 +1078,19 @@ module Net
r and r.length r and r.length
end end
def basic_auth( acc, pass ) def basic_auth( account, password )
@header['authorization'] = 'Basic ' + ["#{acc}:#{pass}"].pack('m').strip @header['authorization'] = basic_encode(account, password)
end end
def proxy_basic_auth( account, password )
header['proxy-authorization'] = basic_encode(account, password)
end
def basic_encode( account, password )
'Basic ' + ["#{account}:#{password}"].pack('m').strip
end
private :basic_encode
end end
@ -1098,16 +1108,14 @@ module Net
@response_has_body = resbody @response_has_body = resbody
@path = path @path = path
@header = tmp = {} @header = {}
return unless initheader return unless initheader
initheader.each do |k,v| initheader.each do |k,v|
key = k.downcase key = k.downcase
if tmp.key? key then $stderr.puts "net/http: WARNING: duplicated HTTP header: #{k}" if @header.key?(key) and $VERBOSE
$stderr.puts "WARNING: duplicated HTTP header: #{k}" if $VERBOSE @header[key] = v.strip
end
tmp[ key ] = v.strip
end end
tmp['accept'] ||= '*/*' @header['accept'] ||= '*/*'
end end
attr_reader :method attr_reader :method
@ -1133,8 +1141,8 @@ module Net
# internal use only # internal use only
def exec( sock, ver, path, body ) def exec( sock, ver, path, body )
if body then if body
check_body_premitted check_body_permitted
send_request_with_body sock, ver, path, body send_request_with_body sock, ver, path, body
else else
request sock, ver, path request sock, ver, path
@ -1143,29 +1151,22 @@ module Net
private private
def check_body_premitted def check_body_permitted
request_body_permitted? or request_body_permitted? or
raise ArgumentError, 'HTTP request body is not premitted' raise ArgumentError, 'HTTP request body is not permitted'
end end
def send_request_with_body( sock, ver, path, body ) def send_request_with_body( sock, ver, path, body )
if block_given? then @header['content-length'] = body.size.to_s
ac = Accumulator.new
yield ac # must be yield, DO NOT USE block.call
data = ac.terminate
else
data = body
end
@header['content-length'] = data.size.to_s
@header.delete 'transfer-encoding' @header.delete 'transfer-encoding'
unless @header['content-type'] then unless @header['content-type']
$stderr.puts 'Content-Type did not set; using application/x-www-form-urlencoded' if $VERBOSE $stderr.puts 'net/http: WARNING: Content-Type did not set; using application/x-www-form-urlencoded' if $VERBOSE
@header['content-type'] = 'application/x-www-form-urlencoded' @header['content-type'] = 'application/x-www-form-urlencoded'
end end
request sock, ver, path request sock, ver, path
sock.write data sock.write body
end end
def request( sock, ver, path ) def request( sock, ver, path )
@ -1455,7 +1456,7 @@ module Net
httpv, code, msg = read_status_line(sock) httpv, code, msg = read_status_line(sock)
res = response_class(code).new(httpv, code, msg) res = response_class(code).new(httpv, code, msg)
each_response_header(sock) do |k,v| each_response_header(sock) do |k,v|
if res.key? k then if res.key? k
res[k] << ', ' << v res[k] << ', ' << v
else else
res[k] = v res[k] = v
@ -1481,11 +1482,9 @@ module Net
end end
def each_response_header( sock ) def each_response_header( sock )
while true do while true
line = sock.readuntil( "\n", true ) # ignore EOF line = sock.readuntil("\n", true).sub(/\s+\z/, '')
line.sub!( /\s+\z/, '' ) # don't use chop!
break if line.empty? break if line.empty?
m = /\A([^:]+):\s*/.match(line) or m = /\A([^:]+):\s*/.match(line) or
raise HTTPBadResponse, 'wrong header line format' raise HTTPBadResponse, 'wrong header line format'
yield m[1], m.post_match yield m[1], m.post_match
@ -1533,7 +1532,7 @@ module Net
end end
def value def value
HTTPSuccess === self or error! error! unless HTTPSuccess === self
end end
# #
@ -1555,21 +1554,23 @@ module Net
def reading_body( sock, reqmethodallowbody ) def reading_body( sock, reqmethodallowbody )
@socket = sock @socket = sock
@body_exist = reqmethodallowbody && self.class.body_permitted? @body_exist = reqmethodallowbody && self.class.body_permitted?
yield begin
self.body yield
@socket = nil self.body # ensure to read body
ensure
@socket = nil
end
end end
def read_body( dest = nil, &block ) def read_body( dest = nil, &block )
if @read then if @read
(dest or block) and raise IOError, "#{self.class}\#read_body called twice" if dest or block
raise IOError, "#{self.class}\#read_body called twice"
return @body return @body
end end
to = procdest(dest, block) to = procdest(dest, block)
stream_check stream_check
if @body_exist then if @body_exist
read_body_0 to read_body_0 to
@body = to @body = to
else else
@ -1586,15 +1587,15 @@ module Net
private private
def read_body_0( dest ) def read_body_0( dest )
if chunked? then if chunked?
read_chunked dest read_chunked dest
else else
clen = content_length clen = content_length()
if clen then if clen
@socket.read clen, dest, true # ignore EOF @socket.read clen, dest, true # ignore EOF
else else
clen = range_length clen = range_length()
if clen then if clen
@socket.read clen, dest @socket.read clen, dest
else else
@socket.read_all dest @socket.read_all dest
@ -1607,28 +1608,28 @@ module Net
len = nil len = nil
total = 0 total = 0
while true do while true
line = @socket.readline line = @socket.readline
m = /[0-9a-fA-F]+/.match(line) hexlen = line.slice(/[0-9a-fA-F]+/) or
m or raise HTTPBadResponse, "wrong chunk size line: #{line}" raise HTTPBadResponse, "wrong chunk size line: #{line}"
len = m[0].hex len = hexlen.hex
break if len == 0 break if len == 0
@socket.read len, dest; total += len @socket.read len, dest; total += len
@socket.read 2 # \r\n @socket.read 2 # \r\n
end end
until @socket.readline.empty? do until @socket.readline.empty?
# none # none
end end
end end
def stream_check def stream_check
@socket.closed? and raise IOError, 'try to read body out of block' raise IOError, 'try to read body out of block' if @socket.closed?
end end
def procdest( dest, block ) def procdest( dest, block )
(dest and block) and raise ArgumentError, 'both of arg and block are given for HTTP method'\
raise ArgumentError, 'both of arg and block are given for HTTP method' if dest and block
if block then if block
ReadAdapter.new(block) ReadAdapter.new(block)
else else
dest || '' dest || ''