uri 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of uri might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +7 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +53 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/uri.rb +104 -0
- data/lib/uri/common.rb +744 -0
- data/lib/uri/file.rb +94 -0
- data/lib/uri/ftp.rb +267 -0
- data/lib/uri/generic.rb +1568 -0
- data/lib/uri/http.rb +88 -0
- data/lib/uri/https.rb +23 -0
- data/lib/uri/ldap.rb +261 -0
- data/lib/uri/ldaps.rb +21 -0
- data/lib/uri/mailto.rb +294 -0
- data/lib/uri/rfc2396_parser.rb +546 -0
- data/lib/uri/rfc3986_parser.rb +125 -0
- data/lib/uri/version.rb +6 -0
- data/uri.gemspec +29 -0
- metadata +67 -0
data/lib/uri/http.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
# = uri/http.rb
|
3
|
+
#
|
4
|
+
# Author:: Akira Yamada <akira@ruby-lang.org>
|
5
|
+
# License:: You can redistribute it and/or modify it under the same term as Ruby.
|
6
|
+
# Revision:: $Id$
|
7
|
+
#
|
8
|
+
# See URI for general documentation
|
9
|
+
#
|
10
|
+
|
11
|
+
require_relative 'generic'
|
12
|
+
|
13
|
+
module URI
|
14
|
+
|
15
|
+
#
|
16
|
+
# The syntax of HTTP URIs is defined in RFC1738 section 3.3.
|
17
|
+
#
|
18
|
+
# Note that the Ruby URI library allows HTTP URLs containing usernames and
|
19
|
+
# passwords. This is not legal as per the RFC, but used to be
|
20
|
+
# supported in Internet Explorer 5 and 6, before the MS04-004 security
|
21
|
+
# update. See <URL:http://support.microsoft.com/kb/834489>.
|
22
|
+
#
|
23
|
+
class HTTP < Generic
|
24
|
+
# A Default port of 80 for URI::HTTP.
|
25
|
+
DEFAULT_PORT = 80
|
26
|
+
|
27
|
+
# An Array of the available components for URI::HTTP.
|
28
|
+
COMPONENT = %i[
|
29
|
+
scheme
|
30
|
+
userinfo host port
|
31
|
+
path
|
32
|
+
query
|
33
|
+
fragment
|
34
|
+
].freeze
|
35
|
+
|
36
|
+
#
|
37
|
+
# == Description
|
38
|
+
#
|
39
|
+
# Creates a new URI::HTTP object from components, with syntax checking.
|
40
|
+
#
|
41
|
+
# The components accepted are userinfo, host, port, path, query, and
|
42
|
+
# fragment.
|
43
|
+
#
|
44
|
+
# The components should be provided either as an Array, or as a Hash
|
45
|
+
# with keys formed by preceding the component names with a colon.
|
46
|
+
#
|
47
|
+
# If an Array is used, the components must be passed in the
|
48
|
+
# order <code>[userinfo, host, port, path, query, fragment]</code>.
|
49
|
+
#
|
50
|
+
# Example:
|
51
|
+
#
|
52
|
+
# uri = URI::HTTP.build(host: 'www.example.com', path: '/foo/bar')
|
53
|
+
#
|
54
|
+
# uri = URI::HTTP.build([nil, "www.example.com", nil, "/path",
|
55
|
+
# "query", 'fragment'])
|
56
|
+
#
|
57
|
+
# Currently, if passed userinfo components this method generates
|
58
|
+
# invalid HTTP URIs as per RFC 1738.
|
59
|
+
#
|
60
|
+
def self.build(args)
|
61
|
+
tmp = Util.make_components_hash(self, args)
|
62
|
+
super(tmp)
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# == Description
|
67
|
+
#
|
68
|
+
# Returns the full path for an HTTP request, as required by Net::HTTP::Get.
|
69
|
+
#
|
70
|
+
# If the URI contains a query, the full path is URI#path + '?' + URI#query.
|
71
|
+
# Otherwise, the path is simply URI#path.
|
72
|
+
#
|
73
|
+
# Example:
|
74
|
+
#
|
75
|
+
# uri = URI::HTTP.build(path: '/foo/bar', query: 'test=true')
|
76
|
+
# uri.request_uri # => "/foo/bar?test=true"
|
77
|
+
#
|
78
|
+
def request_uri
|
79
|
+
return unless @path
|
80
|
+
|
81
|
+
url = @query ? "#@path?#@query" : @path.dup
|
82
|
+
url.start_with?(?/.freeze) ? url : ?/ + url
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
@@schemes['HTTP'] = HTTP
|
87
|
+
|
88
|
+
end
|
data/lib/uri/https.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
# = uri/https.rb
|
3
|
+
#
|
4
|
+
# Author:: Akira Yamada <akira@ruby-lang.org>
|
5
|
+
# License:: You can redistribute it and/or modify it under the same term as Ruby.
|
6
|
+
# Revision:: $Id$
|
7
|
+
#
|
8
|
+
# See URI for general documentation
|
9
|
+
#
|
10
|
+
|
11
|
+
require_relative 'http'
|
12
|
+
|
13
|
+
module URI
|
14
|
+
|
15
|
+
# The default port for HTTPS URIs is 443, and the scheme is 'https:' rather
|
16
|
+
# than 'http:'. Other than that, HTTPS URIs are identical to HTTP URIs;
|
17
|
+
# see URI::HTTP.
|
18
|
+
class HTTPS < HTTP
|
19
|
+
# A Default port of 443 for URI::HTTPS
|
20
|
+
DEFAULT_PORT = 443
|
21
|
+
end
|
22
|
+
@@schemes['HTTPS'] = HTTPS
|
23
|
+
end
|
data/lib/uri/ldap.rb
ADDED
@@ -0,0 +1,261 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
# = uri/ldap.rb
|
3
|
+
#
|
4
|
+
# Author::
|
5
|
+
# Takaaki Tateishi <ttate@jaist.ac.jp>
|
6
|
+
# Akira Yamada <akira@ruby-lang.org>
|
7
|
+
# License::
|
8
|
+
# URI::LDAP is copyrighted free software by Takaaki Tateishi and Akira Yamada.
|
9
|
+
# You can redistribute it and/or modify it under the same term as Ruby.
|
10
|
+
# Revision:: $Id$
|
11
|
+
#
|
12
|
+
# See URI for general documentation
|
13
|
+
#
|
14
|
+
|
15
|
+
require_relative 'generic'
|
16
|
+
|
17
|
+
module URI
|
18
|
+
|
19
|
+
#
|
20
|
+
# LDAP URI SCHEMA (described in RFC2255).
|
21
|
+
#--
|
22
|
+
# ldap://<host>/<dn>[?<attrs>[?<scope>[?<filter>[?<extensions>]]]]
|
23
|
+
#++
|
24
|
+
class LDAP < Generic
|
25
|
+
|
26
|
+
# A Default port of 389 for URI::LDAP.
|
27
|
+
DEFAULT_PORT = 389
|
28
|
+
|
29
|
+
# An Array of the available components for URI::LDAP.
|
30
|
+
COMPONENT = [
|
31
|
+
:scheme,
|
32
|
+
:host, :port,
|
33
|
+
:dn,
|
34
|
+
:attributes,
|
35
|
+
:scope,
|
36
|
+
:filter,
|
37
|
+
:extensions,
|
38
|
+
].freeze
|
39
|
+
|
40
|
+
# Scopes available for the starting point.
|
41
|
+
#
|
42
|
+
# * SCOPE_BASE - the Base DN
|
43
|
+
# * SCOPE_ONE - one level under the Base DN, not including the base DN and
|
44
|
+
# not including any entries under this
|
45
|
+
# * SCOPE_SUB - subtrees, all entries at all levels
|
46
|
+
#
|
47
|
+
SCOPE = [
|
48
|
+
SCOPE_ONE = 'one',
|
49
|
+
SCOPE_SUB = 'sub',
|
50
|
+
SCOPE_BASE = 'base',
|
51
|
+
].freeze
|
52
|
+
|
53
|
+
#
|
54
|
+
# == Description
|
55
|
+
#
|
56
|
+
# Creates a new URI::LDAP object from components, with syntax checking.
|
57
|
+
#
|
58
|
+
# The components accepted are host, port, dn, attributes,
|
59
|
+
# scope, filter, and extensions.
|
60
|
+
#
|
61
|
+
# The components should be provided either as an Array, or as a Hash
|
62
|
+
# with keys formed by preceding the component names with a colon.
|
63
|
+
#
|
64
|
+
# If an Array is used, the components must be passed in the
|
65
|
+
# order <code>[host, port, dn, attributes, scope, filter, extensions]</code>.
|
66
|
+
#
|
67
|
+
# Example:
|
68
|
+
#
|
69
|
+
# uri = URI::LDAP.build({:host => 'ldap.example.com',
|
70
|
+
# :dn => '/dc=example'})
|
71
|
+
#
|
72
|
+
# uri = URI::LDAP.build(["ldap.example.com", nil,
|
73
|
+
# "/dc=example;dc=com", "query", nil, nil, nil])
|
74
|
+
#
|
75
|
+
def self.build(args)
|
76
|
+
tmp = Util::make_components_hash(self, args)
|
77
|
+
|
78
|
+
if tmp[:dn]
|
79
|
+
tmp[:path] = tmp[:dn]
|
80
|
+
end
|
81
|
+
|
82
|
+
query = []
|
83
|
+
[:extensions, :filter, :scope, :attributes].collect do |x|
|
84
|
+
next if !tmp[x] && query.size == 0
|
85
|
+
query.unshift(tmp[x])
|
86
|
+
end
|
87
|
+
|
88
|
+
tmp[:query] = query.join('?')
|
89
|
+
|
90
|
+
return super(tmp)
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# == Description
|
95
|
+
#
|
96
|
+
# Creates a new URI::LDAP object from generic URI components as per
|
97
|
+
# RFC 2396. No LDAP-specific syntax checking is performed.
|
98
|
+
#
|
99
|
+
# Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+,
|
100
|
+
# +opaque+, +query+, and +fragment+, in that order.
|
101
|
+
#
|
102
|
+
# Example:
|
103
|
+
#
|
104
|
+
# uri = URI::LDAP.new("ldap", nil, "ldap.example.com", nil, nil,
|
105
|
+
# "/dc=example;dc=com", nil, "query", nil)
|
106
|
+
#
|
107
|
+
# See also URI::Generic.new.
|
108
|
+
#
|
109
|
+
def initialize(*arg)
|
110
|
+
super(*arg)
|
111
|
+
|
112
|
+
if @fragment
|
113
|
+
raise InvalidURIError, 'bad LDAP URL'
|
114
|
+
end
|
115
|
+
|
116
|
+
parse_dn
|
117
|
+
parse_query
|
118
|
+
end
|
119
|
+
|
120
|
+
# Private method to cleanup +dn+ from using the +path+ component attribute.
|
121
|
+
def parse_dn
|
122
|
+
@dn = @path[1..-1]
|
123
|
+
end
|
124
|
+
private :parse_dn
|
125
|
+
|
126
|
+
# Private method to cleanup +attributes+, +scope+, +filter+, and +extensions+
|
127
|
+
# from using the +query+ component attribute.
|
128
|
+
def parse_query
|
129
|
+
@attributes = nil
|
130
|
+
@scope = nil
|
131
|
+
@filter = nil
|
132
|
+
@extensions = nil
|
133
|
+
|
134
|
+
if @query
|
135
|
+
attrs, scope, filter, extensions = @query.split('?')
|
136
|
+
|
137
|
+
@attributes = attrs if attrs && attrs.size > 0
|
138
|
+
@scope = scope if scope && scope.size > 0
|
139
|
+
@filter = filter if filter && filter.size > 0
|
140
|
+
@extensions = extensions if extensions && extensions.size > 0
|
141
|
+
end
|
142
|
+
end
|
143
|
+
private :parse_query
|
144
|
+
|
145
|
+
# Private method to assemble +query+ from +attributes+, +scope+, +filter+, and +extensions+.
|
146
|
+
def build_path_query
|
147
|
+
@path = '/' + @dn
|
148
|
+
|
149
|
+
query = []
|
150
|
+
[@extensions, @filter, @scope, @attributes].each do |x|
|
151
|
+
next if !x && query.size == 0
|
152
|
+
query.unshift(x)
|
153
|
+
end
|
154
|
+
@query = query.join('?')
|
155
|
+
end
|
156
|
+
private :build_path_query
|
157
|
+
|
158
|
+
# Returns dn.
|
159
|
+
def dn
|
160
|
+
@dn
|
161
|
+
end
|
162
|
+
|
163
|
+
# Private setter for dn +val+.
|
164
|
+
def set_dn(val)
|
165
|
+
@dn = val
|
166
|
+
build_path_query
|
167
|
+
@dn
|
168
|
+
end
|
169
|
+
protected :set_dn
|
170
|
+
|
171
|
+
# Setter for dn +val+.
|
172
|
+
def dn=(val)
|
173
|
+
set_dn(val)
|
174
|
+
val
|
175
|
+
end
|
176
|
+
|
177
|
+
# Returns attributes.
|
178
|
+
def attributes
|
179
|
+
@attributes
|
180
|
+
end
|
181
|
+
|
182
|
+
# Private setter for attributes +val+.
|
183
|
+
def set_attributes(val)
|
184
|
+
@attributes = val
|
185
|
+
build_path_query
|
186
|
+
@attributes
|
187
|
+
end
|
188
|
+
protected :set_attributes
|
189
|
+
|
190
|
+
# Setter for attributes +val+.
|
191
|
+
def attributes=(val)
|
192
|
+
set_attributes(val)
|
193
|
+
val
|
194
|
+
end
|
195
|
+
|
196
|
+
# Returns scope.
|
197
|
+
def scope
|
198
|
+
@scope
|
199
|
+
end
|
200
|
+
|
201
|
+
# Private setter for scope +val+.
|
202
|
+
def set_scope(val)
|
203
|
+
@scope = val
|
204
|
+
build_path_query
|
205
|
+
@scope
|
206
|
+
end
|
207
|
+
protected :set_scope
|
208
|
+
|
209
|
+
# Setter for scope +val+.
|
210
|
+
def scope=(val)
|
211
|
+
set_scope(val)
|
212
|
+
val
|
213
|
+
end
|
214
|
+
|
215
|
+
# Returns filter.
|
216
|
+
def filter
|
217
|
+
@filter
|
218
|
+
end
|
219
|
+
|
220
|
+
# Private setter for filter +val+.
|
221
|
+
def set_filter(val)
|
222
|
+
@filter = val
|
223
|
+
build_path_query
|
224
|
+
@filter
|
225
|
+
end
|
226
|
+
protected :set_filter
|
227
|
+
|
228
|
+
# Setter for filter +val+.
|
229
|
+
def filter=(val)
|
230
|
+
set_filter(val)
|
231
|
+
val
|
232
|
+
end
|
233
|
+
|
234
|
+
# Returns extensions.
|
235
|
+
def extensions
|
236
|
+
@extensions
|
237
|
+
end
|
238
|
+
|
239
|
+
# Private setter for extensions +val+.
|
240
|
+
def set_extensions(val)
|
241
|
+
@extensions = val
|
242
|
+
build_path_query
|
243
|
+
@extensions
|
244
|
+
end
|
245
|
+
protected :set_extensions
|
246
|
+
|
247
|
+
# Setter for extensions +val+.
|
248
|
+
def extensions=(val)
|
249
|
+
set_extensions(val)
|
250
|
+
val
|
251
|
+
end
|
252
|
+
|
253
|
+
# Checks if URI has a path.
|
254
|
+
# For URI::LDAP this will return +false+.
|
255
|
+
def hierarchical?
|
256
|
+
false
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
@@schemes['LDAP'] = LDAP
|
261
|
+
end
|
data/lib/uri/ldaps.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
# = uri/ldap.rb
|
3
|
+
#
|
4
|
+
# License:: You can redistribute it and/or modify it under the same term as Ruby.
|
5
|
+
#
|
6
|
+
# See URI for general documentation
|
7
|
+
#
|
8
|
+
|
9
|
+
require_relative 'ldap'
|
10
|
+
|
11
|
+
module URI
|
12
|
+
|
13
|
+
# The default port for LDAPS URIs is 636, and the scheme is 'ldaps:' rather
|
14
|
+
# than 'ldap:'. Other than that, LDAPS URIs are identical to LDAP URIs;
|
15
|
+
# see URI::LDAP.
|
16
|
+
class LDAPS < LDAP
|
17
|
+
# A Default port of 636 for URI::LDAPS
|
18
|
+
DEFAULT_PORT = 636
|
19
|
+
end
|
20
|
+
@@schemes['LDAPS'] = LDAPS
|
21
|
+
end
|
data/lib/uri/mailto.rb
ADDED
@@ -0,0 +1,294 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
# = uri/mailto.rb
|
3
|
+
#
|
4
|
+
# Author:: Akira Yamada <akira@ruby-lang.org>
|
5
|
+
# License:: You can redistribute it and/or modify it under the same term as Ruby.
|
6
|
+
# Revision:: $Id$
|
7
|
+
#
|
8
|
+
# See URI for general documentation
|
9
|
+
#
|
10
|
+
|
11
|
+
require_relative 'generic'
|
12
|
+
|
13
|
+
module URI
|
14
|
+
|
15
|
+
#
|
16
|
+
# RFC6068, the mailto URL scheme.
|
17
|
+
#
|
18
|
+
class MailTo < Generic
|
19
|
+
include REGEXP
|
20
|
+
|
21
|
+
# A Default port of nil for URI::MailTo.
|
22
|
+
DEFAULT_PORT = nil
|
23
|
+
|
24
|
+
# An Array of the available components for URI::MailTo.
|
25
|
+
COMPONENT = [ :scheme, :to, :headers ].freeze
|
26
|
+
|
27
|
+
# :stopdoc:
|
28
|
+
# "hname" and "hvalue" are encodings of an RFC 822 header name and
|
29
|
+
# value, respectively. As with "to", all URL reserved characters must
|
30
|
+
# be encoded.
|
31
|
+
#
|
32
|
+
# "#mailbox" is as specified in RFC 822 [RFC822]. This means that it
|
33
|
+
# consists of zero or more comma-separated mail addresses, possibly
|
34
|
+
# including "phrase" and "comment" components. Note that all URL
|
35
|
+
# reserved characters in "to" must be encoded: in particular,
|
36
|
+
# parentheses, commas, and the percent sign ("%"), which commonly occur
|
37
|
+
# in the "mailbox" syntax.
|
38
|
+
#
|
39
|
+
# Within mailto URLs, the characters "?", "=", "&" are reserved.
|
40
|
+
|
41
|
+
# ; RFC 6068
|
42
|
+
# hfields = "?" hfield *( "&" hfield )
|
43
|
+
# hfield = hfname "=" hfvalue
|
44
|
+
# hfname = *qchar
|
45
|
+
# hfvalue = *qchar
|
46
|
+
# qchar = unreserved / pct-encoded / some-delims
|
47
|
+
# some-delims = "!" / "$" / "'" / "(" / ")" / "*"
|
48
|
+
# / "+" / "," / ";" / ":" / "@"
|
49
|
+
#
|
50
|
+
# ; RFC3986
|
51
|
+
# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
52
|
+
# pct-encoded = "%" HEXDIG HEXDIG
|
53
|
+
HEADER_REGEXP = /\A(?<hfield>(?:%\h\h|[!$'-.0-;@-Z_a-z~])*=(?:%\h\h|[!$'-.0-;@-Z_a-z~])*)(?:&\g<hfield>)*\z/
|
54
|
+
# practical regexp for email address
|
55
|
+
# https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
|
56
|
+
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/
|
57
|
+
# :startdoc:
|
58
|
+
|
59
|
+
#
|
60
|
+
# == Description
|
61
|
+
#
|
62
|
+
# Creates a new URI::MailTo object from components, with syntax checking.
|
63
|
+
#
|
64
|
+
# Components can be provided as an Array or Hash. If an Array is used,
|
65
|
+
# the components must be supplied as <code>[to, headers]</code>.
|
66
|
+
#
|
67
|
+
# If a Hash is used, the keys are the component names preceded by colons.
|
68
|
+
#
|
69
|
+
# The headers can be supplied as a pre-encoded string, such as
|
70
|
+
# <code>"subject=subscribe&cc=address"</code>, or as an Array of Arrays
|
71
|
+
# like <code>[['subject', 'subscribe'], ['cc', 'address']]</code>.
|
72
|
+
#
|
73
|
+
# Examples:
|
74
|
+
#
|
75
|
+
# require 'uri'
|
76
|
+
#
|
77
|
+
# m1 = URI::MailTo.build(['joe@example.com', 'subject=Ruby'])
|
78
|
+
# m1.to_s # => "mailto:joe@example.com?subject=Ruby"
|
79
|
+
#
|
80
|
+
# m2 = URI::MailTo.build(['john@example.com', [['Subject', 'Ruby'], ['Cc', 'jack@example.com']]])
|
81
|
+
# m2.to_s # => "mailto:john@example.com?Subject=Ruby&Cc=jack@example.com"
|
82
|
+
#
|
83
|
+
# m3 = URI::MailTo.build({:to => 'listman@example.com', :headers => [['subject', 'subscribe']]})
|
84
|
+
# m3.to_s # => "mailto:listman@example.com?subject=subscribe"
|
85
|
+
#
|
86
|
+
def self.build(args)
|
87
|
+
tmp = Util.make_components_hash(self, args)
|
88
|
+
|
89
|
+
case tmp[:to]
|
90
|
+
when Array
|
91
|
+
tmp[:opaque] = tmp[:to].join(',')
|
92
|
+
when String
|
93
|
+
tmp[:opaque] = tmp[:to].dup
|
94
|
+
else
|
95
|
+
tmp[:opaque] = ''
|
96
|
+
end
|
97
|
+
|
98
|
+
if tmp[:headers]
|
99
|
+
query =
|
100
|
+
case tmp[:headers]
|
101
|
+
when Array
|
102
|
+
tmp[:headers].collect { |x|
|
103
|
+
if x.kind_of?(Array)
|
104
|
+
x[0] + '=' + x[1..-1].join
|
105
|
+
else
|
106
|
+
x.to_s
|
107
|
+
end
|
108
|
+
}.join('&')
|
109
|
+
when Hash
|
110
|
+
tmp[:headers].collect { |h,v|
|
111
|
+
h + '=' + v
|
112
|
+
}.join('&')
|
113
|
+
else
|
114
|
+
tmp[:headers].to_s
|
115
|
+
end
|
116
|
+
unless query.empty?
|
117
|
+
tmp[:opaque] << '?' << query
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
super(tmp)
|
122
|
+
end
|
123
|
+
|
124
|
+
#
|
125
|
+
# == Description
|
126
|
+
#
|
127
|
+
# Creates a new URI::MailTo object from generic URL components with
|
128
|
+
# no syntax checking.
|
129
|
+
#
|
130
|
+
# This method is usually called from URI::parse, which checks
|
131
|
+
# the validity of each component.
|
132
|
+
#
|
133
|
+
def initialize(*arg)
|
134
|
+
super(*arg)
|
135
|
+
|
136
|
+
@to = nil
|
137
|
+
@headers = []
|
138
|
+
|
139
|
+
# The RFC3986 parser does not normally populate opaque
|
140
|
+
@opaque = "?#{@query}" if @query && !@opaque
|
141
|
+
|
142
|
+
unless @opaque
|
143
|
+
raise InvalidComponentError,
|
144
|
+
"missing opaque part for mailto URL"
|
145
|
+
end
|
146
|
+
to, header = @opaque.split('?', 2)
|
147
|
+
# allow semicolon as a addr-spec separator
|
148
|
+
# http://support.microsoft.com/kb/820868
|
149
|
+
unless /\A(?:[^@,;]+@[^@,;]+(?:\z|[,;]))*\z/ =~ to
|
150
|
+
raise InvalidComponentError,
|
151
|
+
"unrecognised opaque part for mailtoURL: #{@opaque}"
|
152
|
+
end
|
153
|
+
|
154
|
+
if arg[10] # arg_check
|
155
|
+
self.to = to
|
156
|
+
self.headers = header
|
157
|
+
else
|
158
|
+
set_to(to)
|
159
|
+
set_headers(header)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# The primary e-mail address of the URL, as a String.
|
164
|
+
attr_reader :to
|
165
|
+
|
166
|
+
# E-mail headers set by the URL, as an Array of Arrays.
|
167
|
+
attr_reader :headers
|
168
|
+
|
169
|
+
# Checks the to +v+ component.
|
170
|
+
def check_to(v)
|
171
|
+
return true unless v
|
172
|
+
return true if v.size == 0
|
173
|
+
|
174
|
+
v.split(/[,;]/).each do |addr|
|
175
|
+
# check url safety as path-rootless
|
176
|
+
if /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*\z/ !~ addr
|
177
|
+
raise InvalidComponentError,
|
178
|
+
"an address in 'to' is invalid as URI #{addr.dump}"
|
179
|
+
end
|
180
|
+
|
181
|
+
# check addr-spec
|
182
|
+
# don't s/\+/ /g
|
183
|
+
addr.gsub!(/%\h\h/, URI::TBLDECWWWCOMP_)
|
184
|
+
if EMAIL_REGEXP !~ addr
|
185
|
+
raise InvalidComponentError,
|
186
|
+
"an address in 'to' is invalid as uri-escaped addr-spec #{addr.dump}"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
true
|
191
|
+
end
|
192
|
+
private :check_to
|
193
|
+
|
194
|
+
# Private setter for to +v+.
|
195
|
+
def set_to(v)
|
196
|
+
@to = v
|
197
|
+
end
|
198
|
+
protected :set_to
|
199
|
+
|
200
|
+
# Setter for to +v+.
|
201
|
+
def to=(v)
|
202
|
+
check_to(v)
|
203
|
+
set_to(v)
|
204
|
+
v
|
205
|
+
end
|
206
|
+
|
207
|
+
# Checks the headers +v+ component against either
|
208
|
+
# * HEADER_REGEXP
|
209
|
+
def check_headers(v)
|
210
|
+
return true unless v
|
211
|
+
return true if v.size == 0
|
212
|
+
if HEADER_REGEXP !~ v
|
213
|
+
raise InvalidComponentError,
|
214
|
+
"bad component(expected opaque component): #{v}"
|
215
|
+
end
|
216
|
+
|
217
|
+
true
|
218
|
+
end
|
219
|
+
private :check_headers
|
220
|
+
|
221
|
+
# Private setter for headers +v+.
|
222
|
+
def set_headers(v)
|
223
|
+
@headers = []
|
224
|
+
if v
|
225
|
+
v.split('&').each do |x|
|
226
|
+
@headers << x.split(/=/, 2)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
protected :set_headers
|
231
|
+
|
232
|
+
# Setter for headers +v+.
|
233
|
+
def headers=(v)
|
234
|
+
check_headers(v)
|
235
|
+
set_headers(v)
|
236
|
+
v
|
237
|
+
end
|
238
|
+
|
239
|
+
# Constructs String from URI.
|
240
|
+
def to_s
|
241
|
+
@scheme + ':' +
|
242
|
+
if @to
|
243
|
+
@to
|
244
|
+
else
|
245
|
+
''
|
246
|
+
end +
|
247
|
+
if @headers.size > 0
|
248
|
+
'?' + @headers.collect{|x| x.join('=')}.join('&')
|
249
|
+
else
|
250
|
+
''
|
251
|
+
end +
|
252
|
+
if @fragment
|
253
|
+
'#' + @fragment
|
254
|
+
else
|
255
|
+
''
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
# Returns the RFC822 e-mail text equivalent of the URL, as a String.
|
260
|
+
#
|
261
|
+
# Example:
|
262
|
+
#
|
263
|
+
# require 'uri'
|
264
|
+
#
|
265
|
+
# uri = URI.parse("mailto:ruby-list@ruby-lang.org?Subject=subscribe&cc=myaddr")
|
266
|
+
# uri.to_mailtext
|
267
|
+
# # => "To: ruby-list@ruby-lang.org\nSubject: subscribe\nCc: myaddr\n\n\n"
|
268
|
+
#
|
269
|
+
def to_mailtext
|
270
|
+
to = URI.decode_www_form_component(@to)
|
271
|
+
head = ''
|
272
|
+
body = ''
|
273
|
+
@headers.each do |x|
|
274
|
+
case x[0]
|
275
|
+
when 'body'
|
276
|
+
body = URI.decode_www_form_component(x[1])
|
277
|
+
when 'to'
|
278
|
+
to << ', ' + URI.decode_www_form_component(x[1])
|
279
|
+
else
|
280
|
+
head << URI.decode_www_form_component(x[0]).capitalize + ': ' +
|
281
|
+
URI.decode_www_form_component(x[1]) + "\n"
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
"To: #{to}
|
286
|
+
#{head}
|
287
|
+
#{body}
|
288
|
+
"
|
289
|
+
end
|
290
|
+
alias to_rfc822text to_mailtext
|
291
|
+
end
|
292
|
+
|
293
|
+
@@schemes['MAILTO'] = MailTo
|
294
|
+
end
|