[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]