summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--doc/net/http.rd.ja502
-rw-r--r--lib/net/http.rb79
3 files changed, 565 insertions, 24 deletions
diff --git a/ChangeLog b/ChangeLog
index 9d4d20f124..f95b1113c4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Fri Jul 12 06:34:05 2002 Minero Aoki <aamine@loveruby.net>
+
+ * lib/net/http.rb: rename HTTP.get_uri get_response.
+
+ * lib/net/http.rb: HTTP.get_print accepts URI objects.
+
+ * lib/net/http.rb: HTTP.get did not work with URI.
+
Fri Jul 12 02:15:58 2002 Nobuyoshi Nakada <nobu.nokada@softhome.net>
* string.c (rb_str_match): fix for string match.
diff --git a/doc/net/http.rd.ja b/doc/net/http.rd.ja
new file mode 100644
index 0000000000..0e39329197
--- /dev/null
+++ b/doc/net/http.rd.ja
@@ -0,0 +1,502 @@
+=begin
+
+= net/http.rb
+
+== このライブラリについて
+
+汎用データ転送プロトコル HTTP version 1.1 を扱うライブラリです。
+実装は [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'
+ # or
+ Net::HTTP.get_print URI.parse('http://www.example.com/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'
+
+ def read_uri( uri_str )
+ response = Net::HTTP.get_response(URI.parse(uri_str))
+ case response
+ when Net::HTTPSuccess then response
+ when Net::HTTPRedirection then read_uri(response['location'])
+ else
+ response.error!
+ end
+ end
+
+ print read_uri('http://www.ruby-lang.org')
+
+HTTPSuccess や HTTPRedirection は HTTPResponse クラスの下位クラスです。
+HTTPResponse オブジェクトはそれぞれ HTTP レスポンスのステータスによって
+異るクラスに属しており、そのクラスで結果を分類できます。どのようなクラスが
+用意されているのかについては「HTTP レスポンスクラス群」の節を見てください。
+
+=== Basic 認証
+
+ 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
+ }
+
+=== HTTP レスポンスクラス群
+
+以下に HTTP 1.1 のリザルトコードとそれに対応するレスポンスクラスを
+示します。クラスはすべて Net モジュールの中で定義されており、
+インデントが継承関係を表わしています。
+
+ xxx HTTPResponse
+
+ 1xx HTTPInformation
+ 100 HTTPContinue
+ 101 HTTPSwitchProtocol
+
+ 2xx HTTPSuccess
+ 200 HTTPOK
+ 201 HTTPCreated
+ 202 HTTPAccepted
+ 203 HTTPNonAuthoritativeInformation
+ 204 HTTPNoContent
+ 205 HTTPResetContent
+ 206 HTTPPartialContent
+
+ 3xx HTTPRedirection
+ 300 HTTPMultipleChoice
+ 301 HTTPMovedPermanently
+ 302 HTTPFound
+ 303 HTTPSeeOther
+ 304 HTTPNotModified
+ 305 HTTPUseProxy
+ 307 HTTPTemporaryRedirect
+
+ 4xx HTTPClientError
+ 400 HTTPBadRequest
+ 401 HTTPUnauthorized
+ 402 HTTPPaymentRequired
+ 403 HTTPForbidden
+ 404 HTTPNotFound
+ 405 HTTPMethodNotAllowed
+ 406 HTTPNotAcceptable
+ 407 HTTPProxyAuthenticationRequired
+ 408 HTTPRequestTimeOut
+ 409 HTTPConflict
+ 410 HTTPGone
+ 411 HTTPLengthRequired
+ 412 HTTPPreconditionFailed
+ 413 HTTPRequestEntityTooLarge
+ 414 HTTPRequestURITooLong
+ 415 HTTPUnsupportedMediaType
+ 416 HTTPRequestedRangeNotSatisfiable
+ 417 HTTPExpectationFailed
+
+ 5xx HTTPServerError
+ 500 HTTPInternalServerError
+ 501 HTTPNotImplemented
+ 502 HTTPBadGateway
+ 503 HTTPServiceUnavailable
+ 504 HTTPGatewayTimeOut
+ 505 HTTPVersionNotSupported
+
+ xxx HTTPUnknownResponse
+
+== 新しい仕様への変更と移行措置について
+
+Ruby 1.6 には http.rb 1.1、Ruby 1.7 には http.rb 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 )
+ 新しい Net::HTTP オブジェクトを生成し HTTP セッションを
+ 開始したうえで返します。
+
+: start( address, port = 80, proxy_addr = nil, proxy_port = nil ) {|http| .... }
+ 新しい Net::HTTP オブジェクトを生成しブロックに渡します。
+ ブロック実行中のみ HTTP セッションを維持します。
+
+ ブロックの返り値をそのまま返します。
+
+: get_print( uri )
+: get_print( address, path, port = 80 )
+ uri または address path port で指定されたエンティティを
+ 取得し stdout に出力します。
+
+ Net::HTTP.get_print URI.parse('http://www.example.com')
+
+: get( uri )
+: get( address, path, port = 80 )
+ uri または address path port で指定されたエンティティを
+ 取得し文字列で返します。
+
+ print Net::HTTP.get(URI.parse('http://www.example.com'))
+
+: get_response( uri )
+: get_response( address, path, port = 80 )
+ uri または address path port で指定されたエンティティを
+ 取得し Net::HTTPResponse オブジェクトで返します。
+
+ res = Net::HTTP.get_response(URI.parse('http://www.example.com'))
+ print res.body
+
+: 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 を発生します。
+
+ イテレータとして呼ばれた時はブロックの間だけセッションを
+ 維持し、ブロック終了とともに自動的にセッションを終了します。
+
+: started?
+ 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::HTTPRequest
+
+HTTP リクエストを抽象化するクラス。実際には下位クラスの
+Net::HTTP::Get, Post, Head を使います。
+
+=== クラスメソッド
+
+: 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
diff --git a/lib/net/http.rb b/lib/net/http.rb
index 4bd781bb89..0a1a714a0d 100644
--- a/lib/net/http.rb
+++ b/lib/net/http.rb
@@ -37,13 +37,15 @@ For details of HTTP, refer [RFC2616]
require 'net/http'
Net::HTTP.get_print 'some.www.server', '/index.html'
+ # or
+ Net::HTTP.get_print URI.parse('http://www.example.com/index.html')
=== Posting Form Data
require 'net/http'
Net::HTTP.start( 'some.www.server', 80 ) {|http|
- response = http.post( '/cgi-bin/any.rhtml',
- 'querytype=subject&target=ruby' )
+ response = http.post('/cgi-bin/any.rhtml',
+ 'querytype=subject&target=ruby')
}
=== Accessing via Proxy
@@ -56,22 +58,21 @@ proxy, instead of given host.
$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($proxy_addr, $proxy_port).start('some.www.server') {|http|
+ # always connect to your.proxy.addr:8080
+ :
}
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.
-=== Redirect
+=== Following Redirection
require 'net/http'
- require 'uri'
- def read_uri( uri )
- response = HTTP.get_uri(URI.parse(uri))
+ def read_uri( uri_str )
+ response = Net::HTTP.get_response(URI.parse(uri_str))
case response
when Net::HTTPSuccess then response
when Net::HTTPRedirection then read_uri(response['location'])
@@ -80,7 +81,7 @@ there's no need to change code if there's proxy or not.
end
end
- p read_uri('http://www.ruby-lang.org')
+ print read_uri('http://www.ruby-lang.org')
Net::HTTPSuccess and Net::HTTPRedirection is a HTTPResponse class.
All HTTPResponse objects belong to its own response class which
@@ -192,12 +193,26 @@ This function is not thread-safe.
This method returns the return value of the block.
+: get_print( uri )
+: get_print( address, path, port = 80 )
+ gets entity body from the target and output it to stdout.
+
+ Net::HTTP.get_print URI.parse('http://www.example.com')
+
+: get( uri )
: get( address, path, port = 80 )
- gets entity body from path and returns it.
- return value is a String.
+ send GET request to the target and get a response.
+ This method returns a String.
-: get_print( address, path, port = 80 )
- gets entity body from path and output it to $stdout.
+ print Net::HTTP.get(URI.parse('http://www.example.com'))
+
+: get_response( uri )
+: get_response( address, path, port = 80 )
+ send GET request to the target and get a response.
+ This method returns a Net::HTTPResponse object.
+
+ res = Net::HTTP.get_response(URI.parse('http://www.example.com'))
+ print res.body
: Proxy( address, port = 80 )
creates a HTTP proxy class.
@@ -492,6 +507,7 @@ All arguments named KEY is case-insensitive.
=end
require 'net/protocol'
+require 'uri'
module Net
@@ -534,33 +550,48 @@ module Net
# short cut methods
#
- def HTTP.get_print( addr, path, port = nil )
- new( addr, port || HTTP.default_port ).start {|http|
+ def HTTP.get_print( arg1, arg2 = nil, port = nil )
+ if arg2
+ addr, path = arg1, arg2
+ else
+ uri = arg1
+ addr = uri.host
+ path = uri.request_uri
+ port = uri.port
+ end
+ new(addr, port || HTTP.default_port).start {|http|
http.get path, nil, $stdout
}
nil
end
def HTTP.get( arg1, arg2 = nil, arg3 = nil )
+ get_response(arg1,arg2,arg3).body
+ end
+
+ def HTTP.get_response( arg1, arg2 = nil, arg3 = nil )
if arg2 then
- get_path(arg1, arg2, arg3).body
+ get_by_path(arg1, arg2, arg3)
else
- get_uri(arg1).body
+ get_by_uri(arg1)
end
end
- def HTTP.get_path( addr, path, port = nil )
+ def HTTP.get_by_path( addr, path, port = nil )
new( addr, port || HTTP.default_port ).start {|http|
return http.request(Get.new(path))
}
end
- private_class_method :get_path
+ private_class_method :get_by_path
- def HTTP.get_uri( uri )
- new(uri.addr, uri.port).start {|http|
- return http.request(Get.new(http_path(uri)))
+ def HTTP.get_by_uri( uri )
+ # Should we allow this?
+ # uri = URI.parse(uri) unless uri.respond_to?(:host)
+ new(uri.host, uri.port).start {|http|
+ return http.request(Get.new(uri.request_uri))
}
end
+ private_class_method :get_by_uri
#