mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
f3d9a0cc21
* lib/net/protocol.rb: Protocol#start returns the return value of block. * lib/net/protocol.rb: set timeout limit by default. * lib/net/protocol.rb: new methods WriteAdapter#write, puts, print, printf. * lib/net/http.rb: rename HTTP#get2 to request_get, post2 to request_post ... * lib/net/smtp.rb: should not resolve HELO domain automatically. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1951 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
433 lines
13 KiB
Text
433 lines
13 KiB
Text
=begin
|
|
|
|
= net/http.rb
|
|
|
|
== このライブラリについて
|
|
|
|
汎用データ転送プロトコル HTTP を扱うライブラリです。
|
|
実装は [RFC2616] ((<URL:http://www.ietf.org/rfc/rfc2616.txt>)) に
|
|
基いています。
|
|
|
|
== 使用例
|
|
|
|
=== ウェブサーバからドキュメントを得る (GET)
|
|
|
|
require 'net/http'
|
|
Net::HTTP.start( 'some.www.server', 80 ) {|http|
|
|
response , = http.get('/index.html')
|
|
puts response.body
|
|
}
|
|
|
|
また以下は同じ意味で短く書いたものです。
|
|
|
|
require 'net/http'
|
|
Net::HTTP.get_print 'some.www.server', '/index.html'
|
|
|
|
=== フォームの情報を送信する (POST)
|
|
|
|
require 'net/http'
|
|
Net::HTTP.start( 'some.www.server', 80 ) {|http|
|
|
response , = http.post( '/cgi-bin/any.rhtml',
|
|
'querytype=subject&target=ruby' )
|
|
}
|
|
|
|
=== プロクシ経由のアクセス
|
|
|
|
Net::HTTP のクラスメソッド Net::HTTP.Proxy は、常にプロクシ経由で
|
|
接続するような動作をする、新しいクラスを作成して返します。このクラスは
|
|
Net::HTTP を継承しているので Net::HTTP と全く同じように使えます。
|
|
|
|
require 'net/http'
|
|
|
|
$proxy_addr = 'your.proxy.addr'
|
|
$proxy_port = 8080
|
|
:
|
|
Net::HTTP::Proxy($proxy_addr, $proxy_port).start( 'some.www.server' ) {|http|
|
|
# always connect to your.proxy.addr:8080
|
|
:
|
|
}
|
|
|
|
また Net::HTTP.Proxy は第一引数が nil だと Net::HTTP 自身を返すので
|
|
上のコードのように書いておけばプロクシなしの場合にも対応できます。
|
|
|
|
=== リダイレクトに対応する
|
|
|
|
require 'net/http'
|
|
Net::HTTP.version_1_1
|
|
|
|
host = 'www.ruby-lang.org'
|
|
path = '/'
|
|
begin
|
|
Net::HTTP.start( host, 80 ) {|http|
|
|
response , = http.get(path)
|
|
print response.body
|
|
}
|
|
rescue Net::ProtoRetriableError => err
|
|
if m = %r<http://([^/]+)>.match( err.response['location'] ) then
|
|
host = m[1].strip
|
|
path = m.post_match
|
|
retry
|
|
end
|
|
end
|
|
|
|
この例では URL からホスト名を得るのにいいかげんな方法を使っていますが、
|
|
将来 URI クラスが標準添付になればもっと簡単になるはずです。
|
|
|
|
=== Basic 認証
|
|
|
|
require 'net/http'
|
|
|
|
Net::HTTP.start( 'auth.some.domain' ) {|http|
|
|
response , = http.get( '/need-auth.cgi',
|
|
'Authentication' => ["#{account}:#{password}"].pack('m').strip )
|
|
print response.body
|
|
}
|
|
|
|
バージョン 1.2 (Ruby 1.7 以降に添付) では次のように書けます。
|
|
|
|
require 'net/http'
|
|
|
|
req = Net::HTTP::Get.new('/need-auth.cgi')
|
|
req.basic_auth 'account', 'password'
|
|
Net::HTTP.start( 'auth.some.domain' ) {|http|
|
|
response = http.request(req)
|
|
print response.body
|
|
}
|
|
|
|
== 新しい仕様への変更と移行措置について
|
|
|
|
Ruby 1.6 に入っているのが http.rb 1.1 で 1.7 以降が 1.2 ですが、
|
|
この間ではかなり大きく仕様が変わります。そこで突然に仕様を変更
|
|
するのでなく、両方の実装を並存させる時期を設けることにしました。
|
|
|
|
メソッド HTTP.version_1_2、HTTP.version_1_1 を呼ぶと
|
|
そのあとに生成される Net::HTTP オブジェクトはそれぞれの
|
|
バージョンの仕様で動作するようになります。以下は使用例です。
|
|
|
|
# example
|
|
Net::HTTP.start {|http1| ...(http1 has 1.2 features)... }
|
|
|
|
Net::HTTP.version_1_1
|
|
Net::HTTP.start {|http2| ...(http2 has 1.1 features)... }
|
|
|
|
Net::HTTP.version_1_2
|
|
Net::HTTP.start {|http3| ...(http3 has 1.2 features)... }
|
|
|
|
この機能はスレッドセーフではありません。
|
|
|
|
== class Net::HTTP
|
|
|
|
=== クラスメソッド
|
|
|
|
: new( address, port = 80, proxy_addr = nil, proxy_port = nil )
|
|
新しい HTTP オブジェクトを生成します。address は HTTP サーバーの FQDN で、
|
|
port は接続するポート番号です。このメソッドではまだ接続はしません。
|
|
|
|
proxy_addr を与えるとプロクシを介して接続するオブジェクトを生成します。
|
|
|
|
: start( address, port = 80, proxy_addr = nil, proxy_port = nil )
|
|
: start( address, port = 80, proxy_addr = nil, proxy_port = nil ) {|http| .... }
|
|
以下と同じです。
|
|
|
|
Net::HTTP.new(address, port, proxy_addr, proxy_port).start(&block)
|
|
|
|
: get( address, path, port = 80 )
|
|
ホスト address の port 番ポートに接続して path の表現する
|
|
エンティティを取得、文字列で返します。
|
|
|
|
: get_print( address, path, port = 80 )
|
|
ホスト address の port 番ポートに接続して path の表現する
|
|
エンティティを取得したうえ、$stdout に << で出力します。
|
|
|
|
: Proxy( address, port = 80 )
|
|
常に指定されたプロクシに接続するクラスを作成し返します。
|
|
このクラスは Net::HTTP を継承しているので Net::HTTP と全く
|
|
同じように使えます。
|
|
|
|
address が nil のときは Net::HTTP クラスをそのまま返します。
|
|
|
|
# example
|
|
proxy_class = Net::HTTP::Proxy( 'proxy.foo.org', 8080 )
|
|
:
|
|
proxy_class.start( 'www.ruby-lang.org' ) {|http|
|
|
# connecting proxy.foo.org:8080
|
|
:
|
|
}
|
|
|
|
: proxy_class?
|
|
自身が (Proxy メソッドによって作成された) プロクシ用のクラスならば真。
|
|
|
|
: port
|
|
HTTP のデフォルトポート (80)。
|
|
|
|
=== メソッド
|
|
|
|
: start
|
|
: start {|http| .... }
|
|
TCP コネクションを張り、HTTP セッションを開始します。
|
|
すでにセッションが開始していたら例外 IOError を発生します。
|
|
|
|
イテレータとして呼ばれた時はブロックの間だけセッションを接続し、
|
|
ブロック終了とともに自動的にセッションを閉じます。
|
|
|
|
: active?
|
|
HTTP セッションが開始されていたら真。
|
|
|
|
: address
|
|
接続するアドレス
|
|
|
|
: port
|
|
接続するポート番号
|
|
|
|
: open_timeout
|
|
: open_timeout=(n)
|
|
接続時に待つ最大秒数。この秒数たってもコネクションが
|
|
開かなければ例外 TimeoutError を発生します。
|
|
|
|
: read_timeout
|
|
: read_timeout=(n)
|
|
読みこみ (read(1) 一回) でブロックしてよい最大秒数。
|
|
この秒数たっても読みこめなければ例外 TimeoutError を発生します。
|
|
|
|
: finish
|
|
HTTP セッションを終了します。セッション開始前にこのメソッドが
|
|
呼ばれた場合は例外 IOError を発生します。
|
|
|
|
: proxy?
|
|
プロクシを介して接続するなら真。
|
|
|
|
: proxy_address
|
|
プロクシ経由で接続する HTTP オブジェクトならプロクシのアドレス。
|
|
そうでないなら nil。
|
|
|
|
: proxy_port
|
|
プロクシ経由で接続する HTTP オブジェクトならプロクシのポート。
|
|
そうでないなら nil。
|
|
|
|
: get( path, header = nil )
|
|
: get( path, header = nil ) {|str| .... }
|
|
サーバ上の path にあるエンティティを取得します。また header が nil
|
|
でなければ、リクエストを送るときにその内容を HTTP ヘッダとして書き
|
|
こみます。header はハッシュで、「ヘッダ名 => 内容」のような形式で
|
|
なければいけません。
|
|
|
|
返り値は、バージョン 1.1 では HTTPResponse とエンティティボディ文字列の
|
|
二要素の配列です。1.2 では HTTPResponse ただひとつのみです。この場合、
|
|
エンティティボディは response.body で得られます。
|
|
|
|
ブロックとともに呼ばれた時はエンティティボディを少しづつブロックに
|
|
与えます。
|
|
|
|
1.1 では 3xx (再試行可能なエラー)に対しても例外を発生します。この場合
|
|
HTTPResponse は例外オブジェクトから err.response で得ることができます。
|
|
一方 1.2 では全く例外を発生しません。
|
|
|
|
# version 1.1 (bundled with Ruby 1.6)
|
|
response, body = http.get( '/index.html' )
|
|
|
|
# version 1.2 (bundled with Ruby 1.7 or later)
|
|
response = http.get( '/index.html' )
|
|
|
|
# compatible in both version
|
|
response , = http.get( '/index.html' )
|
|
response.body
|
|
|
|
# using block
|
|
File.open( 'save.txt', 'w' ) {|f|
|
|
http.get( '/~foo/', nil ) do |str|
|
|
f.write str
|
|
end
|
|
}
|
|
|
|
: head( path, header = nil )
|
|
サーバ上の path にあるエンティティのヘッダのみを取得します。
|
|
また header が nil でなければリクエストを送るときにその内容を
|
|
HTTP ヘッダとして書きこみます。header はハッシュで、
|
|
「ヘッダ名 => 内容」のような形式でなければいけません。
|
|
|
|
HTTPResponse オブジェクトを返します。
|
|
|
|
1.1 では 3xx (再試行可能なエラー)に対しても例外を発生します。この場合
|
|
HTTPResponse は例外オブジェクトから err.response で得ることができます。
|
|
一方 1.2 では全く例外を発生しません。
|
|
|
|
response = nil
|
|
Net::HTTP.start( 'some.www.server', 80 ) {|http|
|
|
response = http.head( '/index.html' )
|
|
}
|
|
p response['content-type']
|
|
|
|
: post( path, data, header = nil )
|
|
: post( path, data, header = nil ) {|str| .... }
|
|
サーバ上の path にあるエンティティに対し文字列 data を
|
|
送ります。レスポンスは << メソッドを使って dest に書き
|
|
こまれます。header は get メソッドと同じです。
|
|
HTTPResponse オブジェクトと dest の配列を返します。
|
|
|
|
イテレータとして呼びだされたときはエンティティボディを少しづつ
|
|
ブロックに与えます。
|
|
|
|
1.1 では 3xx (再試行可能なエラー)に対しても例外を発生します。この場合
|
|
HTTPResponse は例外オブジェクトから err.response で得ることができます。
|
|
一方 1.2 では全く例外を発生しません。
|
|
|
|
# version 1.1
|
|
response, body = http.post( '/cgi-bin/search.rb', 'query=subject&target=ruby' )
|
|
|
|
# version 1.2
|
|
response = http.post( '/cgi-bin/search.rb', 'query=subject&target=ruby' )
|
|
|
|
# compatible in both version
|
|
response , = http.post( '/cgi-bin/search.rb', 'query=subject&target=ruby' )
|
|
|
|
# using block
|
|
File.open( 'save.html', 'w' ) {|f|
|
|
http.post( '/cgi-bin/search.rb',
|
|
'query=subject&target=ruby' ) do |str|
|
|
f.write str
|
|
end
|
|
}
|
|
|
|
: request_get( path, header = nil )
|
|
: request_get( path, header = nil ) {|response| .... }
|
|
path にあるエンティティを取得します。HTTPResponse
|
|
オブジェクトを返します。
|
|
|
|
ブロックとともに呼び出されたときは、ブロック実行中は接続を
|
|
維持したまま HTTPResponse オブジェクトをブロックに渡します。
|
|
|
|
このメソッドは HTTP プロトコルに関連した例外は発生させません。
|
|
|
|
# example
|
|
response = http.request_get( '/index.html' )
|
|
p response['content-type']
|
|
puts response.body # body is already read
|
|
|
|
# using block
|
|
http.request_get( '/index.html' ) {|response|
|
|
p response['content-type']
|
|
response.read_body do |str| # read body now
|
|
print str
|
|
end
|
|
}
|
|
|
|
: request_post( path, data, header = nil )
|
|
: request_post( path, data, header = nil ) {|response| .... }
|
|
path にあるエンティティを取得します。HTTPResponse
|
|
オブジェクトを返します。
|
|
|
|
ブロックとともに呼び出されたときは、ボディを読みこむ前に
|
|
HTTPResponse オブジェクトをブロックに渡します。
|
|
|
|
このメソッドは HTTP プロトコルに関連した例外は発生させません。
|
|
|
|
# example
|
|
response = http.post2( '/cgi-bin/nice.rb', 'datadatadata...' )
|
|
p response.status
|
|
puts response.body # body is already read
|
|
|
|
# using block
|
|
http.post2( '/cgi-bin/nice.rb', 'datadatadata...' ) {|response|
|
|
p response.status
|
|
p response['content-type']
|
|
response.read_body do |str| # read body now
|
|
print str
|
|
end
|
|
}
|
|
|
|
: request( request [, data] )
|
|
: request( request [, data] ) {|response| .... }
|
|
HTTPResquest オブジェクト request を送信します。POST/PUT の時は data も
|
|
与えられます (POST/PUT 以外で data を与えると ArgumentError を発生します)。
|
|
|
|
ブロックとともに呼びだされたときはボディを読みこまずに HTTPResponse
|
|
オブジェクトをブロックに与えます。
|
|
|
|
このメソッドは HTTP プロトコルに関連した例外は発生させません。
|
|
|
|
== class Net::HTTP::Get, Head, Post
|
|
|
|
HTTP リクエストを抽象化するクラス。key はすべて大文字小文字を
|
|
区別しません。
|
|
|
|
=== クラスメソッド
|
|
|
|
: new
|
|
HTTP リクエストオブジェクトを生成します。
|
|
|
|
=== メソッド
|
|
|
|
: self[ key ]
|
|
key ヘッダフィールドの文字列。
|
|
key は大文字小文字を区別しません。
|
|
|
|
: self[ key ] = val
|
|
key ヘッダフィールドに val をセットします。
|
|
key は大文字小文字を区別しません。
|
|
|
|
: each {|name, val| .... }
|
|
ヘッダ名とその値に対するくりかえし。ヘッダ名は小文字で統一されます。
|
|
|
|
: basic_auth( account, password )
|
|
Authrization: ヘッダを basic auth 用にセットします。
|
|
|
|
: range
|
|
Range: ヘッダの示す範囲を Range オブジェクトで返します。
|
|
|
|
: range = r
|
|
: set_range( i, len )
|
|
範囲を指定してエンティティを取得するためのヘッダ Range: をセットします。
|
|
r は Range オブジェクト、i, len は始点と長さです。
|
|
|
|
: content_length
|
|
Content-Length: ヘッダの値 (整数)。
|
|
|
|
: content_range
|
|
Content-Range: ヘッダの値 (Range)。
|
|
|
|
== class Net::HTTPResponse
|
|
|
|
HTTP レスポンスのクラスです。
|
|
引数がヘッダフィールド名である場合、大文字小文字を区別しません。
|
|
|
|
=== メソッド
|
|
|
|
: self[ key ]
|
|
key ヘッダフィールド(文字列)です。たとえばキー 'content-length'
|
|
に対しては '2048' のような文字列が得られます。
|
|
key は大文字小文字を区別しません。
|
|
|
|
: self[ key ] = val
|
|
key ヘッダフィールドを value に設定します。
|
|
key は大文字小文字を区別しません。
|
|
|
|
: key?( key )
|
|
key というヘッダフィールドがあれば真。
|
|
key は大文字小文字を区別しません。
|
|
|
|
: each {|name,value| .... }
|
|
すべてのヘッダフィールド名とその値のペアに対するくりかえし。
|
|
|
|
: canonical_each {|name,value| .... }
|
|
ヘッダフィールドの正式名とその値のペアに対して繰り返します。
|
|
|
|
: code
|
|
HTTP のリザルトコードです。例えば '302' などです。
|
|
|
|
: message
|
|
HTTP サーバがリザルトコードに付加して返すメッセージです。
|
|
例えば 'Not Found' などです。
|
|
|
|
: read_body( dest = '' )
|
|
エンティティボディを取得し dest に << メソッドを使って書きこみます。
|
|
同じ HTTPResponse オブジェクトに対して二回以上呼ばれた場合、
|
|
二回目からはなにもせずに一回目の返り値をそのまま返します。
|
|
|
|
: read_body {|str| .... }
|
|
エンティティボディを少しづつ取得して順次ブロックに与えます。
|
|
|
|
: body
|
|
エンティティボディです。read_body を呼んでいればその引数 dest、
|
|
呼んでいなければエンティティボディを文字列として読みこんで返します。
|
|
|
|
=end
|