ruby-changes:34509
From: naruse <ko1@a...>
Date: Sat, 28 Jun 2014 04:26:59 +0900 (JST)
Subject: [ruby-changes:34509] naruse:r46590 (trunk): * lib/uri/mailto.rb: update to latest specs, RFC 6068 and HTML5.
naruse 2014-06-28 04:26:43 +0900 (Sat, 28 Jun 2014) New Revision: 46590 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=46590 Log: * 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. Modified files: trunk/ChangeLog trunk/lib/uri/mailto.rb trunk/test/uri/test_mailto.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 46589) +++ ChangeLog (revision 46590) @@ -1,3 +1,27 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Sat Jun 28 04:08:22 2014 NARUSE, Yui <naruse@r...> + + * 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@i...> * tool/mkconfig.rb: fix empty RbConfig::CONFIG["prefix"] when Index: lib/uri/mailto.rb =================================================================== --- lib/uri/mailto.rb (revision 46589) +++ lib/uri/mailto.rb (revision 46590) @@ -12,7 +12,7 @@ require 'uri/generic' https://github.com/ruby/ruby/blob/trunk/lib/uri/mailto.rb#L12 module URI # - # RFC2368, The mailto URL scheme + # RFC6068, The mailto URL scheme # class MailTo < Generic include REGEXP @@ -37,28 +37,22 @@ module URI https://github.com/ruby/ruby/blob/trunk/lib/uri/mailto.rb#L37 # # Within mailto URLs, the characters "?", "=", "&" are reserved. - # hname = *urlc - # hvalue = *urlc - # header = hname "=" hvalue - HEADER_PATTERN = "(?:[^?=&]*=[^?=&]*)".freeze - HEADER_REGEXP = Regexp.new(HEADER_PATTERN).freeze - # headers = "?" header *( "&" header ) - # to = #mailbox - # mailtoURL = "mailto:" [ to ] [ headers ] - MAILBOX_PATTERN = "(?:#{PATTERN::ESCAPED}|[^(),%?=&])".freeze - MAILTO_REGEXP = Regexp.new(" # :nodoc: - \\A - (#{MAILBOX_PATTERN}*?) (?# 1: to) - (?: - \\? - (#{HEADER_PATTERN}(?:\\&#{HEADER_PATTERN})*) (?# 2: headers) - )? - (?: - \\# - (#{PATTERN::FRAGMENT}) (?# 3: fragment) - )? - \\z - ", Regexp::EXTENDED).freeze + # ; RFC 6068 + # hfields = "?" hfield *( "&" hfield ) + # hfield = hfname "=" hfvalue + # hfname = *qchar + # hfvalue = *qchar + # qchar = unreserved / pct-encoded / some-delims + # some-delims = "!" / "$" / "'" / "(" / ")" / "*" + # / "+" / "," / ";" / ":" / "@" + # + # ; RFC3986 + # unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + # 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 + # 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/ # :startdoc: # @@ -91,31 +85,35 @@ module URI https://github.com/ruby/ruby/blob/trunk/lib/uri/mailto.rb#L85 def self.build(args) tmp = Util::make_components_hash(self, args) - if tmp[:to] - tmp[:opaque] = tmp[:to] + case tmp[:to] + when Array + tmp[:opaque] = tmp[:to].join(',') + when String + tmp[:opaque] = tmp[:to].dup else tmp[:opaque] = '' end if tmp[:headers] - tmp[:opaque] << '?' - - if tmp[:headers].kind_of?(Array) - tmp[:opaque] << tmp[:headers].collect { |x| - if x.kind_of?(Array) - x[0] + '=' + x[1..-1].join - else - x.to_s - end - }.join('&') - - elsif tmp[:headers].kind_of?(Hash) - tmp[:opaque] << tmp[:headers].collect { |h,v| - h + '=' + v - }.join('&') - - else - tmp[:opaque] << tmp[:headers].to_s + query = + case tmp[:headers] + when Array + tmp[:headers].collect { |x| + if x.kind_of?(Array) + x[0] + '=' + x[1..-1].join + else + x.to_s + end + }.join('&') + when Hash + tmp[:headers].collect { |h,v| + h + '=' + v + }.join('&') + else + tmp[:headers].to_s + end + unless query.empty? + tmp[:opaque] << '?' << query end end @@ -137,19 +135,23 @@ module URI https://github.com/ruby/ruby/blob/trunk/lib/uri/mailto.rb#L135 @to = nil @headers = [] - if MAILTO_REGEXP =~ @opaque - if arg[10] # arg_check - self.to = $1 - self.headers = $2 - else - set_to($1) - set_headers($2) - end + to, header = @opaque.split('?', 2) + addrs = to.split(/[,;]/) + # allow semicolon as a addr-spec separator + # http://support.microsoft.com/kb/820868 - else + unless /\A(?:[^@,;]+@[^@,;]+(?:\z|[,;]))*\z/ =~ to raise InvalidComponentError, "unrecognised opaque part for mailtoURL: #{@opaque}" end + + if arg[10] # arg_check + self.to = to + self.headers = header + else + set_to(to) + set_headers(header) + end end # The primary e-mail address of the URL, as a String @@ -158,16 +160,25 @@ module URI https://github.com/ruby/ruby/blob/trunk/lib/uri/mailto.rb#L160 # E-mail headers set by the URL, as an Array of Arrays attr_reader :headers - # check the to +v+ component against either - # * URI::Parser Regexp for :OPAQUE - # * MAILBOX_PATTERN + # check the to +v+ component def check_to(v) return true unless v return true if v.size == 0 - if parser.regexp[:OPAQUE] !~ v || /\A#{MAILBOX_PATTERN}*\z/o !~ v - raise InvalidComponentError, - "bad component(expected opaque component): #{v}" + v.split(/[,;]/).each do |addr| + # check url safety as path-rootless + 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 return true @@ -188,14 +199,11 @@ module URI https://github.com/ruby/ruby/blob/trunk/lib/uri/mailto.rb#L199 end # check the headers +v+ component against either - # * URI::Parser Regexp for :OPAQUE - # * HEADER_PATTERN + # * HEADER_REGEXP def check_headers(v) return true unless v return true if v.size == 0 - - if parser.regexp[:OPAQUE] !~ v || - /\A(#{HEADER_PATTERN}(?:\&#{HEADER_PATTERN})*)\z/o !~ v + if HEADER_REGEXP !~ v raise InvalidComponentError, "bad component(expected opaque component): #{v}" end @@ -208,8 +216,8 @@ module URI https://github.com/ruby/ruby/blob/trunk/lib/uri/mailto.rb#L216 def set_headers(v) @headers = [] if v - v.scan(HEADER_REGEXP) do |x| - @headers << x.split(/=/o, 2) + v.split('&').each do |x| + @headers << x.split(/=/, 2) end end end Index: test/uri/test_mailto.rb =================================================================== --- test/uri/test_mailto.rb (revision 46589) +++ test/uri/test_mailto.rb (revision 46590) @@ -26,6 +26,10 @@ class TestMailTo < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/uri/test_mailto.rb#L26 ok[-1] << ["chris@e...", nil] ok[-1] << {:to => "chris@e..."} + ok << ["mailto:foo+@e...,bar@e..."] + ok[-1] << [["foo+@e...", "bar@e..."], nil] + ok[-1] << {:to => "foo+@e...,bar@e..."} + # mailto:infobot@e...?subject=current-issue ok << ["mailto:infobot@e...?subject=current-issue"] ok[-1] << ["infobot@e...", ["subject=current-issue"]] -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/