* lib/uri/mailto.rb: support RFC6068.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@46528 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
naruse 2014-06-23 20:01:27 +00:00
parent f6dad20e27
commit a672789739
3 changed files with 27 additions and 47 deletions

View File

@ -1,3 +1,7 @@
Tue Jun 24 03:52:35 2014 NARUSE, Yui <naruse@ruby-lang.org>
* lib/uri/mailto.rb: support RFC6068.
Mon Jun 23 18:44:45 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com> Mon Jun 23 18:44:45 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
* tool/config_files.rb: rename class ConfigFiles to Downloader. * tool/config_files.rb: rename class ConfigFiles to Downloader.

View File

@ -12,7 +12,7 @@ require 'uri/generic'
module URI module URI
# #
# RFC2368, The mailto URL scheme # RFC6068, The mailto URL scheme
# #
class MailTo < Generic class MailTo < Generic
include REGEXP include REGEXP
@ -37,28 +37,12 @@ module URI
# #
# Within mailto URLs, the characters "?", "=", "&" are reserved. # Within mailto URLs, the characters "?", "=", "&" are reserved.
# hname = *urlc HEADER_REGEXP = /\A(?<hfield>(?:%\h\h|[!$'-.0-;@-Z_a-z~])*=(?:%\h\h|[!$'-.0-;@-Z_a-z~])*)(?:&\g<hfield>)*\z/
# hvalue = *urlc
# header = hname "=" hvalue
HEADER_PATTERN = "(?:[^?=&]*=[^?=&]*)".freeze
HEADER_REGEXP = Regexp.new(HEADER_PATTERN).freeze
# headers = "?" header *( "&" header ) # headers = "?" header *( "&" header )
# to = #mailbox # to = addr-spec *("," addr-spec )
# mailtoURL = "mailto:" [ to ] [ headers ] # mailtoURI = "mailto:" [ to ] [ hfields ]
MAILBOX_PATTERN = "(?:#{PATTERN::ESCAPED}|[^(),%?=&])".freeze TO_REGEXP = /\A(?:[!#-'*+\-\/-9=?A-Z^-~]+(?:\.[!#-'*+\-\/-9=?A-Z^-~]+)*|"(?:\\[!-~]|[!#-\[\]-~])*")@(?:[!#-'*+\-\/-9=?A-Z^-~]+(?:\.[!#-'*+\-\/-9=?A-Z^-~]+)*|\[[!-Z^-~]*\])\z/
MAILTO_REGEXP = Regexp.new(" # :nodoc: MAILTO_DATA_REGEXP = /\A(?<to>(?<addr-spec>(?<local-part>[!#-'*+\-\/-9=?A-Z^-~]+(?:\.[!#-'*+\-\/-9=?A-Z^-~]+)*|"(?:\\[!-~]|[!#-\[\]-~])*")@(?<domain>[!#-'*+\-\/-9=?A-Z^-~]+(?:\.[!#-'*+\-\/-9=?A-Z^-~]+)*|\[[!-Z^-~]*\]))(?:,\g<addr-spec>)*)?(?<hfields>\?(?<header>(?<hfield>(?:%\h\h|[!$'-.0-;@-Z_a-z~])*=(?:%\h\h|[!$'-.0-;@-Z_a-z~])*)(?:&\g<hfield>)*))?\z/
\\A
(#{MAILBOX_PATTERN}*?) (?# 1: to)
(?:
\\?
(#{HEADER_PATTERN}(?:\\&#{HEADER_PATTERN})*) (?# 2: headers)
)?
(?:
\\#
(#{PATTERN::FRAGMENT}) (?# 3: fragment)
)?
\\z
", Regexp::EXTENDED).freeze
# :startdoc: # :startdoc:
# #
@ -99,8 +83,8 @@ module URI
if tmp[:headers] if tmp[:headers]
tmp[:opaque] << '?' tmp[:opaque] << '?'
case tmp[:headers]
if tmp[:headers].kind_of?(Array) when Array
tmp[:opaque] << tmp[:headers].collect { |x| tmp[:opaque] << tmp[:headers].collect { |x|
if x.kind_of?(Array) if x.kind_of?(Array)
x[0] + '=' + x[1..-1].join x[0] + '=' + x[1..-1].join
@ -108,12 +92,10 @@ module URI
x.to_s x.to_s
end end
}.join('&') }.join('&')
when Hash
elsif tmp[:headers].kind_of?(Hash)
tmp[:opaque] << tmp[:headers].collect { |h,v| tmp[:opaque] << tmp[:headers].collect { |h,v|
h + '=' + v h + '=' + v
}.join('&') }.join('&')
else else
tmp[:opaque] << tmp[:headers].to_s tmp[:opaque] << tmp[:headers].to_s
end end
@ -137,13 +119,13 @@ module URI
@to = nil @to = nil
@headers = [] @headers = []
if MAILTO_REGEXP =~ @opaque if m = MAILTO_DATA_REGEXP.match(@opaque)
if arg[10] # arg_check if arg[10] # arg_check
self.to = $1 self.to = m["to"]
self.headers = $2 self.headers = m["header"]
else else
set_to($1) set_to(m["to"])
set_headers($2) set_headers(m["header"])
end end
else else
@ -158,14 +140,12 @@ module URI
# E-mail headers set by the URL, as an Array of Arrays # E-mail headers set by the URL, as an Array of Arrays
attr_reader :headers attr_reader :headers
# check the to +v+ component against either # check the to +v+ component
# * URI::Parser Regexp for :OPAQUE
# * MAILBOX_PATTERN
def check_to(v) def check_to(v)
return true unless v return true unless v
return true if v.size == 0 return true if v.size == 0
if parser.regexp[:OPAQUE] !~ v || /\A#{MAILBOX_PATTERN}*\z/o !~ v if TO_REGEXP !~ v
raise InvalidComponentError, raise InvalidComponentError,
"bad component(expected opaque component): #{v}" "bad component(expected opaque component): #{v}"
end end
@ -188,14 +168,13 @@ module URI
end end
# check the headers +v+ component against either # check the headers +v+ component against either
# * URI::Parser Regexp for :OPAQUE # * URI::Parser Regexp for :QUERY
# * HEADER_PATTERN # * HEADER_REGEXP
def check_headers(v) def check_headers(v)
return true unless v return true unless v
return true if v.size == 0 return true if v.size == 0
if parser.regexp[:QUERY] !~ v ||
if parser.regexp[:OPAQUE] !~ v || HEADER_REGEXP !~ v
/\A(#{HEADER_PATTERN}(?:\&#{HEADER_PATTERN})*)\z/o !~ v
raise InvalidComponentError, raise InvalidComponentError,
"bad component(expected opaque component): #{v}" "bad component(expected opaque component): #{v}"
end end
@ -208,8 +187,8 @@ module URI
def set_headers(v) def set_headers(v)
@headers = [] @headers = []
if v if v
v.scan(HEADER_REGEXP) do |x| v.split('&').each do |x|
@headers << x.split(/=/o, 2) @headers << x.split(/=/, 2)
end end
end end
end end

View File

@ -100,9 +100,6 @@ class TestMailTo < Test::Unit::TestCase
# mailto:javascript:alert() # mailto:javascript:alert()
bad << ["javascript:alert()", []] bad << ["javascript:alert()", []]
# '=' which is in hname or hvalue is wrong.
bad << ["foo@example.jp?subject=1+1=2", []]
ok.each do |x| ok.each do |x|
assert_equal(x[0], assert_equal(x[0],
@u.build(x[1]).to_s) @u.build(x[1]).to_s)
@ -111,7 +108,7 @@ class TestMailTo < Test::Unit::TestCase
end end
bad.each do |x| bad.each do |x|
assert_raise(URI::InvalidComponentError) { assert_raise(URI::InvalidComponentError, %[URI::MailTo.build(#{x.inspect})]) {
@u.build(x) @u.build(x)
} }
end end