10: def handle(ctx, params)
11: raise ArgumentError.new('uri must be specified') unless params[:uri]
12: params[:uri] = params[:uri].dup if params[:uri].is_a?(URI)
13: uri = params[:uri]
14: referer = params[:referer]
15: unless uri.is_a?(URI)
16: uri = uri.to_s.strip.gsub(/[^#{0.chr}-#{126.chr}]/) { |match|
17: if RUBY_VERSION >= "1.9.0"
18: CGI.escape(match)
19: else
20: sprintf('%%%X', match.unpack($KCODE == 'UTF8' ? 'U' : 'c')[0])
21: end
22: }
23:
24: escaped_uri = Util.html_unescape(
25: uri.split(/(?:%[0-9A-Fa-f]{2})+|#/).zip(
26: uri.scan(/(?:%[0-9A-Fa-f]{2})+|#/)
27: ).map { |x,y|
28: "#{URI.escape(x)}#{y}"
29: }.join('')
30: )
31:
32: begin
33: uri = URI.parse(escaped_uri)
34: rescue
35: uri = URI.parse(URI.escape(escaped_uri))
36: end
37:
38: end
39: uri = @scheme_handlers[
40: uri.relative? ? 'relative' : uri.scheme.downcase
41: ].call(uri, params[:referer])
42:
43: if params[:referer] && params[:referer].uri
44: if uri.path.length == 0 && uri.relative?
45: uri.path = params[:referer].uri.path
46: end
47: end
48:
49: uri.path = '/' if uri.path.length == 0
50:
51: if uri.relative?
52: raise 'need absolute URL' unless referer && referer.uri
53: base = nil
54: if referer.respond_to?(:bases) && referer.parser
55: base = referer.bases.last
56: end
57:
58: uri = ((base && base.uri && base.uri.absolute?) ?
59: base.uri :
60: referer.uri) + uri
61: uri = referer.uri + uri
62:
63: uri.path.sub!(/^(\/\.\.)+(?=\/)/, '')
64: end
65:
66: unless ['http', 'https', 'file'].include?(uri.scheme.downcase)
67: raise "unsupported scheme: #{uri.scheme}"
68: end
69: params[:uri] = uri
70:
71: super
72: end