From 6eaa5f2b05c17cf05db5ced5e24f818e99a39828 Mon Sep 17 00:00:00 2001 From: akr Date: Mon, 24 Nov 2003 14:36:18 +0000 Subject: [PATCH] * lib/open-uri.rb (OpenURI.open_loop, URI::HTTP#proxy_open): use catch/throw for redirection instead of exception. (OpenURI.open_loop, OpenURI.redirectable?): restrict redirection. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5015 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 ++++++ lib/open-uri.rb | 54 ++++++++++++++++++++++++++++--------------------- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index ae4d54c484..77b0998c94 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Mon Nov 24 23:32:06 2003 Tanaka Akira + + * lib/open-uri.rb (OpenURI.open_loop, URI::HTTP#proxy_open): use + catch/throw for redirection instead of exception. + (OpenURI.open_loop, OpenURI.redirectable?): restrict redirection. + Mon Nov 24 19:59:48 2003 Tanaka Akira * lib/open-uri.rb (URI::Generic#find_proxy): use CGI_HTTP_PROXY diff --git a/lib/open-uri.rb b/lib/open-uri.rb index 871b7b490e..5aaa5c4f9c 100644 --- a/lib/open-uri.rb +++ b/lib/open-uri.rb @@ -159,36 +159,44 @@ module OpenURI end uri_set = {} - begin - buf = Buffer.new - if proxy_uri = find_proxy.call(uri) - proxy_uri.proxy_open(buf, uri, options) + buf = nil + while true + redirect = catch(:open_uri_redirect) { + buf = Buffer.new + if proxy_uri = find_proxy.call(uri) + proxy_uri.proxy_open(buf, uri, options) + else + uri.direct_open(buf, options) + end + nil + } + if redirect + if redirect.relative? + # Although it violates RFC 2616, Location: field may have relative + # URI. It is converted to absolute URI using uri. + redirect = uri + redirect + end + unless OpenURI.redirectable?(uri, redirect) + raise "redirection forbidden: #{uri} -> #{redirect}" + end + uri = redirect + raise "HTTP redirection loop: #{uri}" if uri_set.include? uri.to_s + uri_set[uri.to_s] = true else - uri.direct_open(buf, options) + break end - rescue Redirect - loc = $!.uri - if loc.relative? - # Although it violates RFC 2616, Location: field may have relative URI. - # It is converted to absolute URI using uri. - loc = uri + loc - end - uri = loc - raise "HTTP redirection loop: #{uri}" if uri_set.include? uri.to_s - uri_set[uri.to_s] = true - retry end io = buf.io io.base_uri = uri io end - class Redirect < StandardError # :nodoc: - def initialize(uri) - super("redirection to #{uri.to_s}") - @uri = uri - end - attr_reader :uri + def OpenURI.redirectable?(uri1, uri2) # :nodoc: + # This test is intended to forbid a redirection from http://... to + # file:///etc/passwd. + # However this is ad hoc. It should be extensible/configurable. + uri1.scheme.downcase == uri2.scheme.downcase || + (/\A(?:http|ftp)\z/i =~ uri1.scheme && /\A(?:http|ftp)\z/i =~ uri2.scheme) end class HTTPError < StandardError @@ -502,7 +510,7 @@ module URI Net::HTTPFound, # 302 Net::HTTPSeeOther, # 303 Net::HTTPTemporaryRedirect # 307 - raise OpenURI::Redirect.new(URI.parse(resp['location'])) + throw :open_uri_redirect, URI.parse(resp['location']) else raise OpenURI::HTTPError.new(io.status.join(' '), io) end