diff --git a/lib/net/http.rb b/lib/net/http.rb index 93199e09f6..38dca6a440 100644 --- a/lib/net/http.rb +++ b/lib/net/http.rb @@ -1,157 +1,27 @@ # # = net/http.rb # -#-- # Copyright (c) 1999-2003 Yukihiro Matsumoto # Copyright (c) 1999-2003 Minero Aoki # -# written & maintained by Minero Aoki . +# Written & maintained by Minero Aoki . +# # This file is derived from "http-access.rb". +# +# Documented by Minero Aoki; converted to RDoc by William Webber. # # This program is free software. You can re-distribute and/or # modify this program under the same terms of ruby itself --- -# Ruby Distribute License or GNU General Public License. +# Ruby Distribution License or GNU General Public License. +# +# See Net:::HTTP for an overview and examples. # # NOTE: You can find Japanese version of this document here: -# (()) +# http://www.ruby-lang.org/ja/man-1.6/?cmd=view;name=net%2Fhttp.rb # +#-- # $Id$ #++ -# -# == What Is This Library? -# -# This library provides your program functions to access WWW -# documents via HTTP, Hyper Text Transfer Protocol version 1.1. -# For details of HTTP, refer [RFC2616] -# (()). -# -# == Examples -# -# === Getting Document From WWW Server -# -# (formal version) -# -# require 'net/http' -# Net::HTTP.start('www.example.com', 80) {|http| -# response = http.get('/index.html') -# puts response.body -# } -# -# (shorter version) -# -# require 'net/http' -# Net::HTTP.get_print 'www.example.com', '/index.html' -# -# or -# -# require 'net/http' -# require 'uri' -# 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/search.rb', 'query=ruby') -# } -# -# === Accessing via Proxy -# -# Net::HTTP.Proxy creates http proxy class. It has same -# methods of Net::HTTP but its instances always connect to -# proxy, instead of given host. -# -# require 'net/http' -# -# proxy_addr = 'your.proxy.host' -# proxy_port = 8080 -# : -# Net::HTTP::Proxy(proxy_addr, proxy_port).start('www.example.com') {|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. -# -# There are two additional parameters in Net::HTTP.Proxy which allow to -# specify proxy user name and password: -# -# Net::HTTP::Proxy(proxy_addr, proxy_port, proxy_user = nil, proxy_pass = nil) -# -# You may use them to work with authorization-enabled proxies: -# -# require 'net/http' -# require 'uri' -# -# proxy_host = 'your.proxy.host' -# proxy_port = 8080 -# uri = URI.parse(ENV['http_proxy']) -# proxy_user, proxy_pass = uri.userinfo.split(/:/) if uri.userinfo -# 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 -# : -# } -# -# -# === Following Redirection -# -# 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 -# -# response = Net::HTTP.get_response(URI.parse(uri_str)) -# case response -# when Net::HTTPSuccess then response -# when Net::HTTPRedirection then fetch(response['location'], limit - 1) -# else -# response.error! -# end -# end -# -# print fetch('http://www.ruby-lang.org') -# -# Net::HTTPSuccess and Net::HTTPRedirection is a HTTPResponse class. -# All HTTPResponse objects belong to its own response class which -# indicate HTTP result status. For details of response classes, -# see section "HTTP Response Classes". -# -# === Basic Authentication -# -# require 'net/http' -# -# Net::HTTP.start('www.example.com') {|http| -# req = Net::HTTP::Get.new('/secret-page.html') -# req.basic_auth 'account', 'password' -# response = http.request(req) -# print response.body -# } -# -# === HTTP Response Classes -# -# TODO: write me. -# -# == Switching Net::HTTP versions -# -# You can use net/http.rb 1.1 features (bundled with Ruby 1.6) -# by calling HTTP.version_1_1. Calling Net::HTTP.version_1_2 -# allows you to use 1.2 features again. -# -# # 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)... } -# -# This function is NOT multithread-safe. -# require 'net/protocol' require 'uri' @@ -164,11 +34,139 @@ module Net # :nodoc: class HTTPHeaderSyntaxError < StandardError; end # :startdoc: + # == What Is This Library? + # + # This library provides your program functions to access WWW + # documents via HTTP, Hyper Text Transfer Protocol version 1.1. + # For details of HTTP, refer [RFC2616] + # (()). + # + # == Examples + # + # === Getting Document From WWW Server + # + # (formal version) + # + # require 'net/http' + # Net::HTTP.start('www.example.com', 80) { |http| + # response = http.get('/index.html') + # puts response.body + # } + # + # (shorter version) + # + # require 'net/http' + # Net::HTTP.get_print 'www.example.com', '/index.html' + # + # or + # + # require 'net/http' + # require 'uri' + # 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/search.rb', 'query=ruby') + # } + # + # === Accessing via Proxy + # + # Net::HTTP.Proxy creates http proxy class. It has same + # methods of Net::HTTP but its instances always connect to + # proxy, instead of given host. + # + # require 'net/http' + # + # proxy_addr = 'your.proxy.host' + # proxy_port = 8080 + # : + # Net::HTTP::Proxy(proxy_addr, proxy_port).start('www.example.com') {|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. + # + # There are two additional parameters in Net::HTTP.Proxy which allow to + # specify proxy user name and password: + # + # Net::HTTP::Proxy(proxy_addr, proxy_port, proxy_user = nil, proxy_pass = nil) + # + # You may use them to work with authorization-enabled proxies: + # + # require 'net/http' + # require 'uri' + # + # proxy_host = 'your.proxy.host' + # proxy_port = 8080 + # uri = URI.parse(ENV['http_proxy']) + # proxy_user, proxy_pass = uri.userinfo.split(/:/) if uri.userinfo + # 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 + # : + # } + # + # + # === Following Redirection + # + # 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 + # + # response = Net::HTTP.get_response(URI.parse(uri_str)) + # case response + # when Net::HTTPSuccess then response + # when Net::HTTPRedirection then fetch(response['location'], limit - 1) + # else + # response.error! + # end + # end + # + # print fetch('http://www.ruby-lang.org') + # + # Net::HTTPSuccess and Net::HTTPRedirection is a HTTPResponse class. + # All HTTPResponse objects belong to its own response class which + # indicate HTTP result status. For details of response classes, + # see section "HTTP Response Classes". + # + # === Basic Authentication + # + # require 'net/http' + # + # Net::HTTP.start('www.example.com') {|http| + # req = Net::HTTP::Get.new('/secret-page.html') + # req.basic_auth 'account', 'password' + # response = http.request(req) + # print response.body + # } + # + # === HTTP Response Classes # - # Class providing both short-cut class methods for retrieving entities, - # and instance methods for fuller HTTP functionality. - # - # See comment to the file http.rb for examples of usage. + # TODO: write me. + # + # == Switching Net::HTTP versions + # + # You can use net/http.rb 1.1 features (bundled with Ruby 1.6) + # by calling HTTP.version_1_1. Calling Net::HTTP.version_1_2 + # allows you to use 1.2 features again. + # + # # 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)... } + # + # This function is NOT thread-safe. # class HTTP < Protocol @@ -190,7 +188,7 @@ module Net # :nodoc: @@newimpl = true end - # Turns on net/http 1.2 (ruby 1.8) features. + # Turns on net/http 1.1 (ruby 1.6) features. # Defaults to OFF in ruby 1.8. def HTTP.version_1_1 @@newimpl = false @@ -359,7 +357,7 @@ module Net # :nodoc: end # *WARNING* This method causes serious security hole. - # Never use this method in product code. + # Never use this method in production code. # # Set an output stream for debugging. # diff --git a/lib/net/imap.rb b/lib/net/imap.rb index 0463665bd5..475c2ad0de 100644 --- a/lib/net/imap.rb +++ b/lib/net/imap.rb @@ -1,181 +1,15 @@ +# # = net/imap.rb # -#-- # Copyright (C) 2000 Shugo Maeda # # This library is distributed under the terms of the Ruby license. # You can freely distribute/modify this library. -#++ # -# == IMAP OVERVIEW +# Documentation: Shugo Maeda, with RDoc conversion and overview by William +# Webber. # -# An IMAP client connects to a server, and then authenticates -# itself using either #authenticate() or #login(). Having -# authenticated itself, there is a range of commands -# available to it. Most work with mailboxes, which may be -# arranged in an hierarchical namespace, and each of which -# contains zero or more messages. How this is implemented on -# the server is implementation-dependent; on a UNIX server, it -# will frequently be implemented as a files in mailbox format -# within a hierarchy of directories. -# -# To work on the messages within a mailbox, the client must -# first select that mailbox, using either #select() or (for -# read-only access) #examine(). Once the client has successfully -# selected a mailbox, they enter _selected_ state, and that -# mailbox becomes the _current_ mailbox, on which mail-item -# related commands implicitly operate. -# -# Messages have two sorts of identifiers: message sequence -# numbers, and UIDs. -# -# Message sequence numbers number messages within a mail box -# from 1 up to the number of items in the mail box. If new -# message arrives during a session, it receives a sequence -# number equal to the new size of the mail box. If messages -# are expunged from the mailbox, remaining messages have their -# sequence numbers "shuffled down" to fill the gaps. -# -# UIDs, on the other hand, are permanently guaranteed not to -# identify another message within the same mailbox, even if -# the existing message is deleted. UIDs are required to -# be assigned in ascending (but not necessarily sequential) -# order within a mailbox; this means that if a non-IMAP client -# rearranges the order of mailitems within a mailbox, the -# UIDs have to be reassigned. An IMAP client cannot thus -# rearrange message orders. -# -# == EXAMPLES OF USAGE -# -# === List sender and subject of all recent messages in the default mailbox -# -# imap = Net::IMAP.new('mail.example.com') -# imap.authenticate('LOGIN', 'joe_user', 'joes_password') -# imap.examine('INBOX') -# imap.search(["RECENT"]).each do |message_id| -# envelope = imap.fetch(message_id, "ENVELOPE")[0].attr["ENVELOPE"] -# puts "#{envelope.from[0].name}: \t#{envelope.subject}" -# end -# -# === Move all messages from April 2003 from "Mail/sent-mail" to "Mail/sent-apr03" -# -# imap = Net::IMAP.new('mail.example.com') -# imap.authenticate('LOGIN', 'joe_user', 'joes_password') -# imap.select('Mail/sent-mail') -# if not imap.list('Mail/', 'sent-apr03') -# imap.create('Mail/sent-apr03') -# end -# imap.search(["BEFORE", "30-Apr-2003", "SINCE", "1-Apr-2003"]).each do |message_id| -# imap.copy(message_id, "Mail/sent-apr03") -# imap.store(message_id, "+FLAGS", [:Deleted]) -# end -# imap.expunge -# -# == THREAD-SAFENESS -# -# Net::IMAP supports concurrent threads. For example, -# -# imap = Net::IMAP.new("imap.foo.net", "imap2") -# imap.authenticate("cram-md5", "bar", "password") -# imap.select("inbox") -# fetch_thread = Thread.start { imap.fetch(1..-1, "UID") } -# search_result = imap.search(["BODY", "hello"]) -# fetch_result = fetch_thread.value -# imap.disconnect -# -# This script invokes the FETCH command and the SEARCH command concurrently. -# -# == ERRORS -# -# An IMAP server can send three different types of responses to indicate -# failure: -# -# NO:: the attempted command could not be successfully completed. For -# instance, the username/password used for logging in are incorrect; -# the selected mailbox does not exists; etc. -# -# BAD:: the request from the client does not follow the server's -# understanding of the IMAP protocol. This includes attempting -# commands from the wrong client state; for instance, attempting -# to perform a SEARCH command without having SELECTed a current -# mailbox. It can also signal an internal server -# failure (such as a disk crash) has occurred. -# -# BYE:: the server is saying goodbye. This can be part of a normal -# logout sequence, and can be used as part of a login sequence -# to indicate that the server is (for some reason) unwilling -# to accept our connection. As a response to any other command, -# it indicates either that the server is shutting down, or that -# the server is timing out the client connection due to inactivity. -# -# These three error response are represented by the errors -# Net::IMAP::NoResponseError, Net::IMAP::BadResponseError, and -# Net::IMAP::ByeResponseError, all of which are subclasses of -# Net::IMAP::ResponseError. Essentially, all methods that involve -# sending a request to the server can generate one of these errors. -# Only the most pertinent instances have been documented below. -# -# Because the IMAP class uses Sockets for communication, its methods -# are also susceptible to the various errors that can occur when -# working with sockets. These are generally represented as -# Errno errors. For instance, any method that involves sending a -# request to the server and/or receiving a response from it could -# raise an Errno::EPIPE error if the network connection unexpectedly -# goes down. See the socket(7), ip(7), tcp(7), socket(2), connect(2), -# and associated man pages. -# -# Finally, a Net::IMAP::DataFormatError is thrown if low-level data -# is found to be in an incorrect format (for instance, when converting -# between UTF-8 and UTF-16), and Net::IMAP::ResponseParseError is -# thrown if a server response is non-parseable. -# -# -# == References -# -# [[IMAP]] -# M. Crispin, "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1", -# RFC 2060, December 1996. (Note: since obsoleted by RFC 3501) -# -# [[LANGUAGE-TAGS]] -# Alvestrand, H., "Tags for the Identification of -# Languages", RFC 1766, March 1995. -# -# [[MD5]] -# Myers, J., and M. Rose, "The Content-MD5 Header Field", RFC -# 1864, October 1995. -# -# [[MIME-IMB]] -# Freed, N., and N. Borenstein, "MIME (Multipurpose Internet -# Mail Extensions) Part One: Format of Internet Message Bodies", RFC -# 2045, November 1996. -# -# [[RFC-822]] -# Crocker, D., "Standard for the Format of ARPA Internet Text -# Messages", STD 11, RFC 822, University of Delaware, August 1982. -# -# [[RFC-2087]] -# Myers, J., "IMAP4 QUOTA extension", RFC 2087, January 1997. -# -# [[RFC-2086]] -# Myers, J., "IMAP4 ACL extension", RFC 2086, January 1997. -# -# [[RFC-2195]] -# Klensin, J., Catoe, R., and Krumviede, P., "IMAP/POP AUTHorize Extension -# for Simple Challenge/Response", RFC 2195, September 1997. -# -# [[SORT-THREAD-EXT]] -# Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - SORT and THREAD -# Extensions", draft-ietf-imapext-sort, May 2003. -# -# [[OSSL]] -# http://www.openssl.org -# -# [[RSSL]] -# http://savannah.gnu.org/projects/rubypki -# -# [[UTF7]] -# Goldsmith, D. and Davis, M., "UTF-7: A Mail-Safe Transformation Format of -# Unicode", RFC 2152, May 1997. + require "socket" require "monitor" @@ -187,10 +21,180 @@ end module Net # :nodoc: + # # Net::IMAP implements Internet Message Access Protocol (IMAP) client # functionality. The protocol is described in [IMAP]. # - # See comment to the file imap.rb for examples of usage. + # == IMAP OVERVIEW + # + # An IMAP client connects to a server, and then authenticates + # itself using either #authenticate() or #login(). Having + # authenticated itself, there is a range of commands + # available to it. Most work with mailboxes, which may be + # arranged in an hierarchical namespace, and each of which + # contains zero or more messages. How this is implemented on + # the server is implementation-dependent; on a UNIX server, it + # will frequently be implemented as a files in mailbox format + # within a hierarchy of directories. + # + # To work on the messages within a mailbox, the client must + # first select that mailbox, using either #select() or (for + # read-only access) #examine(). Once the client has successfully + # selected a mailbox, they enter _selected_ state, and that + # mailbox becomes the _current_ mailbox, on which mail-item + # related commands implicitly operate. + # + # Messages have two sorts of identifiers: message sequence + # numbers, and UIDs. + # + # Message sequence numbers number messages within a mail box + # from 1 up to the number of items in the mail box. If new + # message arrives during a session, it receives a sequence + # number equal to the new size of the mail box. If messages + # are expunged from the mailbox, remaining messages have their + # sequence numbers "shuffled down" to fill the gaps. + # + # UIDs, on the other hand, are permanently guaranteed not to + # identify another message within the same mailbox, even if + # the existing message is deleted. UIDs are required to + # be assigned in ascending (but not necessarily sequential) + # order within a mailbox; this means that if a non-IMAP client + # rearranges the order of mailitems within a mailbox, the + # UIDs have to be reassigned. An IMAP client cannot thus + # rearrange message orders. + # + # == EXAMPLES OF USAGE + # + # === List sender and subject of all recent messages in the default mailbox + # + # imap = Net::IMAP.new('mail.example.com') + # imap.authenticate('LOGIN', 'joe_user', 'joes_password') + # imap.examine('INBOX') + # imap.search(["RECENT"]).each do |message_id| + # envelope = imap.fetch(message_id, "ENVELOPE")[0].attr["ENVELOPE"] + # puts "#{envelope.from[0].name}: \t#{envelope.subject}" + # end + # + # === Move all messages from April 2003 from "Mail/sent-mail" to "Mail/sent-apr03" + # + # imap = Net::IMAP.new('mail.example.com') + # imap.authenticate('LOGIN', 'joe_user', 'joes_password') + # imap.select('Mail/sent-mail') + # if not imap.list('Mail/', 'sent-apr03') + # imap.create('Mail/sent-apr03') + # end + # imap.search(["BEFORE", "30-Apr-2003", "SINCE", "1-Apr-2003"]).each do |message_id| + # imap.copy(message_id, "Mail/sent-apr03") + # imap.store(message_id, "+FLAGS", [:Deleted]) + # end + # imap.expunge + # + # == THREAD-SAFENESS + # + # Net::IMAP supports concurrent threads. For example, + # + # imap = Net::IMAP.new("imap.foo.net", "imap2") + # imap.authenticate("cram-md5", "bar", "password") + # imap.select("inbox") + # fetch_thread = Thread.start { imap.fetch(1..-1, "UID") } + # search_result = imap.search(["BODY", "hello"]) + # fetch_result = fetch_thread.value + # imap.disconnect + # + # This script invokes the FETCH command and the SEARCH command concurrently. + # + # == ERRORS + # + # An IMAP server can send three different types of responses to indicate + # failure: + # + # NO:: the attempted command could not be successfully completed. For + # instance, the username/password used for logging in are incorrect; + # the selected mailbox does not exists; etc. + # + # BAD:: the request from the client does not follow the server's + # understanding of the IMAP protocol. This includes attempting + # commands from the wrong client state; for instance, attempting + # to perform a SEARCH command without having SELECTed a current + # mailbox. It can also signal an internal server + # failure (such as a disk crash) has occurred. + # + # BYE:: the server is saying goodbye. This can be part of a normal + # logout sequence, and can be used as part of a login sequence + # to indicate that the server is (for some reason) unwilling + # to accept our connection. As a response to any other command, + # it indicates either that the server is shutting down, or that + # the server is timing out the client connection due to inactivity. + # + # These three error response are represented by the errors + # Net::IMAP::NoResponseError, Net::IMAP::BadResponseError, and + # Net::IMAP::ByeResponseError, all of which are subclasses of + # Net::IMAP::ResponseError. Essentially, all methods that involve + # sending a request to the server can generate one of these errors. + # Only the most pertinent instances have been documented below. + # + # Because the IMAP class uses Sockets for communication, its methods + # are also susceptible to the various errors that can occur when + # working with sockets. These are generally represented as + # Errno errors. For instance, any method that involves sending a + # request to the server and/or receiving a response from it could + # raise an Errno::EPIPE error if the network connection unexpectedly + # goes down. See the socket(7), ip(7), tcp(7), socket(2), connect(2), + # and associated man pages. + # + # Finally, a Net::IMAP::DataFormatError is thrown if low-level data + # is found to be in an incorrect format (for instance, when converting + # between UTF-8 and UTF-16), and Net::IMAP::ResponseParseError is + # thrown if a server response is non-parseable. + # + # + # == References + # + # [[IMAP]] + # M. Crispin, "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1", + # RFC 2060, December 1996. (Note: since obsoleted by RFC 3501) + # + # [[LANGUAGE-TAGS]] + # Alvestrand, H., "Tags for the Identification of + # Languages", RFC 1766, March 1995. + # + # [[MD5]] + # Myers, J., and M. Rose, "The Content-MD5 Header Field", RFC + # 1864, October 1995. + # + # [[MIME-IMB]] + # Freed, N., and N. Borenstein, "MIME (Multipurpose Internet + # Mail Extensions) Part One: Format of Internet Message Bodies", RFC + # 2045, November 1996. + # + # [[RFC-822]] + # Crocker, D., "Standard for the Format of ARPA Internet Text + # Messages", STD 11, RFC 822, University of Delaware, August 1982. + # + # [[RFC-2087]] + # Myers, J., "IMAP4 QUOTA extension", RFC 2087, January 1997. + # + # [[RFC-2086]] + # Myers, J., "IMAP4 ACL extension", RFC 2086, January 1997. + # + # [[RFC-2195]] + # Klensin, J., Catoe, R., and Krumviede, P., "IMAP/POP AUTHorize Extension + # for Simple Challenge/Response", RFC 2195, September 1997. + # + # [[SORT-THREAD-EXT]] + # Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - SORT and THREAD + # Extensions", draft-ietf-imapext-sort, May 2003. + # + # [[OSSL]] + # http://www.openssl.org + # + # [[RSSL]] + # http://savannah.gnu.org/projects/rubypki + # + # [[UTF7]] + # Goldsmith, D. and Davis, M., "UTF-7: A Mail-Safe Transformation Format of + # Unicode", RFC 2152, May 1997. + # class IMAP include MonitorMixin if defined?(OpenSSL)