summaryrefslogtreecommitdiff
path: root/lib/open-uri.rb
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-11-24 08:02:36 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-11-24 08:02:36 +0000
commit483ac5644036ec1f1cf6e74b773c9315c611c8b3 (patch)
tree69bf35cfb695a1d85b5e77e42d6d05f20178a6cf /lib/open-uri.rb
parentf14589947e38ec0290098305612dbcdc5c5ee362 (diff)
* lib/open-uri.rb: validate option names.
:content_length_proc and :progress_proc option implemented. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5012 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/open-uri.rb')
-rw-r--r--lib/open-uri.rb130
1 files changed, 122 insertions, 8 deletions
diff --git a/lib/open-uri.rb b/lib/open-uri.rb
index f13f1d5edb..42503f15cf 100644
--- a/lib/open-uri.rb
+++ b/lib/open-uri.rb
@@ -91,6 +91,22 @@ module Kernel
end
module OpenURI
+ Options = {
+ :proxy => true,
+ :progress_proc => true,
+ :content_length_proc => true,
+ }
+
+
+ def OpenURI.check_options(options) # :nodoc:
+ options.each {|k, v|
+ next unless Symbol === k
+ unless Options.include? k
+ raise ArgumentError, "unrecognized option: #{k}"
+ end
+ }
+ end
+
def OpenURI.scan_open_optional_arguments(*rest) # :nodoc:
if !rest.empty? && (String === rest.first || Integer === rest.first)
mode = rest.shift
@@ -106,6 +122,8 @@ module OpenURI
mode, perm, rest = OpenURI.scan_open_optional_arguments(*rest)
options = rest.shift if !rest.empty? && Hash === rest.first
raise ArgumentError.new("extra arguments") if !rest.empty?
+ options ||= {}
+ OpenURI.check_options(options)
unless mode == nil ||
mode == 'r' || mode == 'rb' ||
@@ -113,7 +131,7 @@ module OpenURI
raise ArgumentError.new("invalid access mode #{mode} (#{uri.class} resource is read only.)")
end
- io = open_loop(uri, options || {})
+ io = open_loop(uri, options)
if block_given?
begin
yield io
@@ -316,12 +334,90 @@ module OpenURI
# Mixin for HTTP and FTP URIs.
module OpenRead
- # opens the URI.
+ # OpenURI::OpenRead#open provides `open' for URI::HTTP and URI::FTP.
+ #
+ # OpenURI::OpenRead#open takes optional 3 arguments as:
+ # OpenURI::OpenRead#open([mode [, perm]] [, options]) [{|io| ... }]
+ #
+ # `mode', `perm' is same as Kernel#open.
+ #
+ # However, `mode' must be read mode because OpenURI::OpenRead#open doesn't
+ # support write mode (yet).
+ # Also `perm' is just ignored because it is meaningful only for file
+ # creation.
+ #
+ # `options' must be a hash.
+ #
+ # Each pairs which key is a string in the hash specify a extra header
+ # field for HTTP.
+ # I.e. it is ignored for FTP without HTTP proxy.
+ #
+ # The hash may include other option which key is a symbol:
+ #
+ # :proxy => "http://proxy.foo.com:8000/"
+ # :proxy => URI.parse("http://proxy.foo.com:8000/")
+ # :proxy => true
+ # :proxy => false
+ # :proxy => nil
+ #
+ # If :proxy option is specified, the value should be String, URI,
+ # boolean or nil.
+ # When String or URI is given, it is treated as proxy URI.
+ # When true is given or the option itself is not specified,
+ # environment variable `scheme_proxy'(or `SCHEME_PROXY') is examined.
+ # `scheme' is replaced by `http' or `ftp'.
+ # When false or nil is given, the environment variables are ignored and
+ # connection will be made to a server directly.
+ #
+ # :content_length_proc => lambda {|content_length| ... }
+ #
+ # If :content_length_proc option is specified, the option value procedure
+ # is called before actual transfer is started.
+ # It takes one argument which is expected content length in bytes.
+ #
+ # If two or more transfer is done by HTTP redirection, the procedure
+ # is called only one for a last transfer.
+ #
+ # When expected content length is unknown, the procedure is called with
+ # nil.
+ # It is happen when HTTP response has no Content-Length header.
+ #
+ # :progress_proc => lambda {|size| ...}
+ #
+ # If :progress_proc option is specified, the proc is called with one
+ # argument each time when `open' gets content fragment from network.
+ # The argument `size' `size' is a accumulated transfered size in bytes.
+ #
+ # If two or more transfer is done by HTTP redirection, the procedure
+ # is called only one for a last transfer.
+ #
+ # :progress_proc and :content_length_proc are intended to be used for
+ # progress bar.
+ # For example, it can be implemented as follows using Ruby/ProgressBar.
+ #
+ # pbar = nil
+ # open("http://...",
+ # :content_length_proc => lambda {|t|
+ # if t && 0 < t
+ # pbar = ProgressBar.new("...", t)
+ # pbar.file_transfer_mode
+ # end
+ # },
+ # :progress_proc => lambda {|s|
+ # pbar.set s if pbar
+ # }) {|f| ... }
+ #
+ # OpenURI::OpenRead#open returns an IO like object if block is not given.
+ # Otherwise it yields the IO object and return the value of the block.
+ # The IO object is extended with OpenURI::Meta.
def open(*rest, &block)
OpenURI.open_uri(self, *rest, &block)
end
- # reads a content of the URI.
+ # OpenURI::OpenRead#read([options]) reads a content referenced by self and
+ # returns the content as string.
+ # The string is extended with OpenURI::Meta.
+ # The argument `options' is same as OpenURI::OpenRead#open.
def read(options={})
self.open(options) {|f|
str = f.read
@@ -369,11 +465,25 @@ module URI
options.each {|k, v| header[k] = v if String === k }
require 'net/http'
- resp = Net::HTTP.start(self.host, self.port) {|http|
- http.get(uri.to_s, header) {|str|
- buf << str
- }
- }
+ resp = nil
+ Net::HTTP.start(self.host, self.port) {|http|
+ http.request_get(uri.to_s, header) {|response|
+ resp = response
+ if options[:content_length_proc] && Net::HTTPSuccess === resp
+ if resp.key?('Content-Length')
+ options[:content_length_proc].call(resp['Content-Length'].to_i)
+ else
+ options[:content_length_proc].call(nil)
+ end
+ end
+ resp.read_body {|str|
+ buf << str
+ if options[:progress_proc] && Net::HTTPSuccess === resp
+ options[:progress_proc].call(buf.size)
+ end
+ }
+ }
+ }
io = buf.io
io.rewind
io.status = [resp.code, resp.message]
@@ -403,8 +513,12 @@ module URI
ftp = Net::FTP.open(self.host)
ftp.login(user, passwd)
+ if options[:content_length_proc]
+ options[:content_length_proc].call(ftp.size(self.path))
+ end
ftp.getbinaryfile(self.path, '/dev/null', Net::FTP::DEFAULT_BLOCKSIZE) {|str|
buf << str
+ options[:progress_proc].call(buf.size) if options[:progress_proc]
}
ftp.close
buf.io.rewind