* lib/uri/mailto.rb: update to latest specs, RFC 6068 and HTML5.
* lib/uri/mailto.rb (HEADER_PATTERN): removed. * lib/uri/mailto.rb (HEADER_REGEXP): use RFC 6068 hfields. * lib/uri/mailto.rb (EMAIL_REGEXP): use HTML5 email regexp. * lib/uri/mailto.rb (URI::MailTo.build): support multiple to addresses. * lib/uri/mailto.rb (URI::MailTo#initialize): Support multiple to addresses. Don't check with regexp, only split. * lib/uri/mailto.rb (URI::MailTo#check_to): verify by matching URI path-rootless and HTML5 email regexp with unescaped one. * lib/uri/mailto.rb (URI::MailTo#check_headers): verify only by HEADER_REGEXP. * lib/uri/mailto.rb (URI::MailTo#set_headers): don't check by HEADER_REGEXP, only split it. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@46590 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
402d33fc44
commit
e63ab5d3ad
24
ChangeLog
24
ChangeLog
@ -1,3 +1,27 @@
|
|||||||
|
Sat Jun 28 04:08:22 2014 NARUSE, Yui <naruse@ruby-lang.org>
|
||||||
|
|
||||||
|
* lib/uri/mailto.rb: update to latest specs, RFC 6068 and HTML5.
|
||||||
|
|
||||||
|
* lib/uri/mailto.rb (HEADER_PATTERN): removed.
|
||||||
|
|
||||||
|
* lib/uri/mailto.rb (HEADER_REGEXP): use RFC 6068 hfields.
|
||||||
|
|
||||||
|
* lib/uri/mailto.rb (EMAIL_REGEXP): use HTML5 email regexp.
|
||||||
|
|
||||||
|
* lib/uri/mailto.rb (URI::MailTo.build): support multiple to addresses.
|
||||||
|
|
||||||
|
* lib/uri/mailto.rb (URI::MailTo#initialize): Support multiple to
|
||||||
|
addresses. Don't check with regexp, only split.
|
||||||
|
|
||||||
|
* lib/uri/mailto.rb (URI::MailTo#check_to): verify by matching
|
||||||
|
URI path-rootless and HTML5 email regexp with unescaped one.
|
||||||
|
|
||||||
|
* lib/uri/mailto.rb (URI::MailTo#check_headers): verify only by
|
||||||
|
HEADER_REGEXP.
|
||||||
|
|
||||||
|
* lib/uri/mailto.rb (URI::MailTo#set_headers): don't check by
|
||||||
|
HEADER_REGEXP, only split it.
|
||||||
|
|
||||||
Sat Jun 28 00:35:10 2014 Lauri Tirkkonen <lotheac@iki.fi>
|
Sat Jun 28 00:35:10 2014 Lauri Tirkkonen <lotheac@iki.fi>
|
||||||
|
|
||||||
* tool/mkconfig.rb: fix empty RbConfig::CONFIG["prefix"] when
|
* tool/mkconfig.rb: fix empty RbConfig::CONFIG["prefix"] when
|
||||||
|
@ -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,22 @@ module URI
|
|||||||
#
|
#
|
||||||
# Within mailto URLs, the characters "?", "=", "&" are reserved.
|
# Within mailto URLs, the characters "?", "=", "&" are reserved.
|
||||||
|
|
||||||
# hname = *urlc
|
# ; RFC 6068
|
||||||
# hvalue = *urlc
|
# hfields = "?" hfield *( "&" hfield )
|
||||||
# header = hname "=" hvalue
|
# hfield = hfname "=" hfvalue
|
||||||
HEADER_PATTERN = "(?:[^?=&]*=[^?=&]*)".freeze
|
# hfname = *qchar
|
||||||
HEADER_REGEXP = Regexp.new(HEADER_PATTERN).freeze
|
# hfvalue = *qchar
|
||||||
# headers = "?" header *( "&" header )
|
# qchar = unreserved / pct-encoded / some-delims
|
||||||
# to = #mailbox
|
# some-delims = "!" / "$" / "'" / "(" / ")" / "*"
|
||||||
# mailtoURL = "mailto:" [ to ] [ headers ]
|
# / "+" / "," / ";" / ":" / "@"
|
||||||
MAILBOX_PATTERN = "(?:#{PATTERN::ESCAPED}|[^(),%?=&])".freeze
|
#
|
||||||
MAILTO_REGEXP = Regexp.new(" # :nodoc:
|
# ; RFC3986
|
||||||
\\A
|
# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||||
(#{MAILBOX_PATTERN}*?) (?# 1: to)
|
# pct-encoded = "%" HEXDIG HEXDIG
|
||||||
(?:
|
HEADER_REGEXP = /\A(?<hfield>(?:%\h\h|[!$'-.0-;@-Z_a-z~])*=(?:%\h\h|[!$'-.0-;@-Z_a-z~])*)(?:&\g<hfield>)*\z/
|
||||||
\\?
|
# practical regexp for email address
|
||||||
(#{HEADER_PATTERN}(?:\\&#{HEADER_PATTERN})*) (?# 2: headers)
|
# http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#valid-e-mail-address
|
||||||
)?
|
EMAIL_REGEXP = /\A[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\z/
|
||||||
(?:
|
|
||||||
\\#
|
|
||||||
(#{PATTERN::FRAGMENT}) (?# 3: fragment)
|
|
||||||
)?
|
|
||||||
\\z
|
|
||||||
", Regexp::EXTENDED).freeze
|
|
||||||
# :startdoc:
|
# :startdoc:
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -91,31 +85,35 @@ module URI
|
|||||||
def self.build(args)
|
def self.build(args)
|
||||||
tmp = Util::make_components_hash(self, args)
|
tmp = Util::make_components_hash(self, args)
|
||||||
|
|
||||||
if tmp[:to]
|
case tmp[:to]
|
||||||
tmp[:opaque] = tmp[:to]
|
when Array
|
||||||
|
tmp[:opaque] = tmp[:to].join(',')
|
||||||
|
when String
|
||||||
|
tmp[:opaque] = tmp[:to].dup
|
||||||
else
|
else
|
||||||
tmp[:opaque] = ''
|
tmp[:opaque] = ''
|
||||||
end
|
end
|
||||||
|
|
||||||
if tmp[:headers]
|
if tmp[:headers]
|
||||||
tmp[:opaque] << '?'
|
query =
|
||||||
|
case tmp[:headers]
|
||||||
if tmp[:headers].kind_of?(Array)
|
when Array
|
||||||
tmp[:opaque] << tmp[:headers].collect { |x|
|
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
|
||||||
else
|
else
|
||||||
x.to_s
|
x.to_s
|
||||||
end
|
end
|
||||||
}.join('&')
|
}.join('&')
|
||||||
|
when Hash
|
||||||
elsif tmp[:headers].kind_of?(Hash)
|
tmp[:headers].collect { |h,v|
|
||||||
tmp[:opaque] << tmp[:headers].collect { |h,v|
|
h + '=' + v
|
||||||
h + '=' + v
|
}.join('&')
|
||||||
}.join('&')
|
else
|
||||||
|
tmp[:headers].to_s
|
||||||
else
|
end
|
||||||
tmp[:opaque] << tmp[:headers].to_s
|
unless query.empty?
|
||||||
|
tmp[:opaque] << '?' << query
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -137,19 +135,23 @@ module URI
|
|||||||
@to = nil
|
@to = nil
|
||||||
@headers = []
|
@headers = []
|
||||||
|
|
||||||
if MAILTO_REGEXP =~ @opaque
|
to, header = @opaque.split('?', 2)
|
||||||
if arg[10] # arg_check
|
addrs = to.split(/[,;]/)
|
||||||
self.to = $1
|
# allow semicolon as a addr-spec separator
|
||||||
self.headers = $2
|
# http://support.microsoft.com/kb/820868
|
||||||
else
|
|
||||||
set_to($1)
|
|
||||||
set_headers($2)
|
|
||||||
end
|
|
||||||
|
|
||||||
else
|
unless /\A(?:[^@,;]+@[^@,;]+(?:\z|[,;]))*\z/ =~ to
|
||||||
raise InvalidComponentError,
|
raise InvalidComponentError,
|
||||||
"unrecognised opaque part for mailtoURL: #{@opaque}"
|
"unrecognised opaque part for mailtoURL: #{@opaque}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if arg[10] # arg_check
|
||||||
|
self.to = to
|
||||||
|
self.headers = header
|
||||||
|
else
|
||||||
|
set_to(to)
|
||||||
|
set_headers(header)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# The primary e-mail address of the URL, as a String
|
# The primary e-mail address of the URL, as a String
|
||||||
@ -158,16 +160,25 @@ 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
|
v.split(/[,;]/).each do |addr|
|
||||||
raise InvalidComponentError,
|
# check url safety as path-rootless
|
||||||
"bad component(expected opaque component): #{v}"
|
if /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*\z/ !~ addr
|
||||||
|
raise InvalidComponentError,
|
||||||
|
"an address in 'to' is invalid as URI #{addr.dump}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# check addr-spec
|
||||||
|
# don't s/\+/ /g
|
||||||
|
addr.gsub!(/%\h\h/, URI::TBLDECWWWCOMP_)
|
||||||
|
if EMAIL_REGEXP !~ addr
|
||||||
|
raise InvalidComponentError,
|
||||||
|
"an address in 'to' is invalid as uri-escaped addr-spec #{addr.dump}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -188,14 +199,11 @@ module URI
|
|||||||
end
|
end
|
||||||
|
|
||||||
# check the headers +v+ component against either
|
# check the headers +v+ component against either
|
||||||
# * URI::Parser Regexp for :OPAQUE
|
# * HEADER_REGEXP
|
||||||
# * HEADER_PATTERN
|
|
||||||
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 HEADER_REGEXP !~ v
|
||||||
if parser.regexp[:OPAQUE] !~ 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 +216,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
|
||||||
|
@ -26,6 +26,10 @@ class TestMailTo < Test::Unit::TestCase
|
|||||||
ok[-1] << ["chris@example.com", nil]
|
ok[-1] << ["chris@example.com", nil]
|
||||||
ok[-1] << {:to => "chris@example.com"}
|
ok[-1] << {:to => "chris@example.com"}
|
||||||
|
|
||||||
|
ok << ["mailto:foo+@example.com,bar@example.com"]
|
||||||
|
ok[-1] << [["foo+@example.com", "bar@example.com"], nil]
|
||||||
|
ok[-1] << {:to => "foo+@example.com,bar@example.com"}
|
||||||
|
|
||||||
# mailto:infobot@example.com?subject=current-issue
|
# mailto:infobot@example.com?subject=current-issue
|
||||||
ok << ["mailto:infobot@example.com?subject=current-issue"]
|
ok << ["mailto:infobot@example.com?subject=current-issue"]
|
||||||
ok[-1] << ["infobot@example.com", ["subject=current-issue"]]
|
ok[-1] << ["infobot@example.com", ["subject=current-issue"]]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user