domain_name 0.5.2 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,9 @@
1
1
  class DomainName
2
+ ETLD_DATA = {
3
+ <% etld_data.each_pair { |key, value| %> <%= key.inspect %> => <%= value.inspect %>,
4
+ <% } %> }
5
+
2
6
  def self.etld_data
3
- @@etld_data ||= {
4
- <% etld_data.each_pair { |key, value| %> <%= key.inspect %> => <%= value.inspect %>,
5
- <% } %> }
7
+ ETLD_DATA
6
8
  end
7
9
  end
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # punycode.rb - PunyCode encoder for the Domain Name library
4
4
  #
5
- # Copyright (C) 2011 Akinori MUSHA, All rights reserved.
5
+ # Copyright (C) 2011, 2012 Akinori MUSHA, All rights reserved.
6
6
  #
7
7
  # Ported from puny.c, a part of VeriSign XCode (encode/decode) IDN
8
8
  # Library.
@@ -58,125 +58,230 @@ class DomainName
58
58
  INITIAL_N = 0x80
59
59
  DELIMITER = '-'
60
60
 
61
- # The maximum value of an DWORD variable
62
- MAXINT = (1 << 64) - 1
61
+ MAXINT = (1 << 32) - 1
63
62
 
64
- # Used in the calculation of bias:
65
63
  LOBASE = BASE - TMIN
66
-
67
- # Used in the calculation of bias:
68
64
  CUTOFF = LOBASE * TMAX / 2
69
65
 
70
- class Error < StandardError; end
71
- class BufferOverflowError < Error; end
72
-
73
- # Returns the basic code point whose value (when used for
74
- # representing integers) is d, which must be in the range 0 to
75
- # BASE-1. The lowercase form is used unless flag is true, in
76
- # which case the uppercase form is used. The behavior is
77
- # undefined if flag is nonzero and digit d has no uppercase form.
78
- def encode_digit(d, flag)
79
- (d + 22 + (d < 26 ? 75 : 0) - (flag ? (1 << 5) : 0)).chr
80
- # 0..25 map to ASCII a..z or A..Z
81
- # 26..35 map to ASCII 0..9
82
- end
83
- module_function :encode_digit
66
+ RE_NONBASIC = /[^\x00-\x7f]/
67
+
68
+ DECODE_DIGIT = {}.tap { |map|
69
+ # ASCII A..Z map to 0..25
70
+ # ASCII a..z map to 0..25
71
+ (0..25).each { |i| map[65 + i] = map[97 + i] = i }
72
+ # ASCII 0..9 map to 26..35
73
+ (26..35).each { |i| map[22 + i] = i }
74
+ }
84
75
 
85
- # Main encode function
86
- def encode(string)
87
- input = string.unpack('U*')
88
- output = ''
76
+ # Most errors we raise are basically kind of ArgumentError.
77
+ class ArgumentError < ::ArgumentError; end
78
+ class BufferOverflowError < ArgumentError; end
89
79
 
90
- # Initialize the state
91
- n = INITIAL_N
92
- delta = 0
93
- bias = INITIAL_BIAS;
80
+ class << self
81
+ private
94
82
 
95
- # Handle the basic code points
96
- input.each { |cp| output << cp.chr if cp < 0x80 }
83
+ # Returns the basic code point whose value (when used for
84
+ # representing integers) is d, which must be in the range 0 to
85
+ # BASE-1. The lowercase form is used unless flag is true, in
86
+ # which case the uppercase form is used. The behavior is
87
+ # undefined if flag is nonzero and digit d has no uppercase
88
+ # form.
89
+ def encode_digit(d, flag)
90
+ (d + 22 + (d < 26 ? 75 : 0) - (flag ? (1 << 5) : 0)).chr
91
+ # 0..25 map to ASCII a..z or A..Z
92
+ # 26..35 map to ASCII 0..9
93
+ end
97
94
 
98
- h = b = output.length
95
+ # Returns the numeric value of a basic code point (for use in
96
+ # representing integers) in the range 0 to base-1, or nil if cp
97
+ # is does not represent a value.
98
+ def decode_digit(cp)
99
+ DECODE_DIGIT[cp]
100
+ end
99
101
 
100
- # h is the number of code points that have been handled, b is the
101
- # number of basic code points, and out is the number of characters
102
- # that have been output.
102
+ public
103
103
 
104
- output << DELIMITER if b > 0
104
+ # Encode a +string+ in Punycode
105
+ def encode(string)
106
+ input = string.unpack('U*')
107
+ output = ''
105
108
 
106
- # Main encoding loop
109
+ # Initialize the state
110
+ n = INITIAL_N
111
+ delta = 0
112
+ bias = INITIAL_BIAS
107
113
 
108
- while h < input.length
109
- # All non-basic code points < n have been handled already. Find
110
- # the next larger one
114
+ # Handle the basic code points
115
+ input.each { |cp| output << cp.chr if cp < 0x80 }
111
116
 
112
- m = MAXINT
113
- input.each { |cp|
114
- m = cp if (n...m) === cp
115
- }
117
+ h = b = output.length
118
+
119
+ # h is the number of code points that have been handled, b is the
120
+ # number of basic code points, and out is the number of characters
121
+ # that have been output.
122
+
123
+ output << DELIMITER if b > 0
124
+
125
+ # Main encoding loop
126
+
127
+ while h < input.length
128
+ # All non-basic code points < n have been handled already. Find
129
+ # the next larger one
130
+
131
+ m = MAXINT
132
+ input.each { |cp|
133
+ m = cp if (n...m) === cp
134
+ }
116
135
 
117
- # Increase delta enough to advance the decoder's <n,i> state to
118
- # <m,0>, but guard against overflow
136
+ # Increase delta enough to advance the decoder's <n,i> state to
137
+ # <m,0>, but guard against overflow
119
138
 
120
- if m - n > (MAXINT - delta) / (h + 1)
121
- raise BufferOverflowError
139
+ delta += (m - n) * (h + 1)
140
+ raise BufferOverflowError if delta > MAXINT
141
+ n = m
142
+
143
+ input.each { |cp|
144
+ # AMC-ACE-Z can use this simplified version instead
145
+ if cp < n
146
+ delta += 1
147
+ raise BufferOverflowError if delta > MAXINT
148
+ elsif cp == n
149
+ # Represent delta as a generalized variable-length integer
150
+ q = delta
151
+ k = BASE
152
+ loop {
153
+ t = k <= bias ? TMIN : k - bias >= TMAX ? TMAX : k - bias
154
+ break if q < t
155
+ q, r = (q - t).divmod(BASE - t)
156
+ output << encode_digit(t + r, false)
157
+ k += BASE
158
+ }
159
+
160
+ output << encode_digit(q, false)
161
+
162
+ # Adapt the bias
163
+ delta = h == b ? delta / DAMP : delta >> 1
164
+ delta += delta / (h + 1)
165
+ bias = 0
166
+ while delta > CUTOFF
167
+ delta /= LOBASE
168
+ bias += BASE
169
+ end
170
+ bias += (LOBASE + 1) * delta / (delta + SKEW)
171
+
172
+ delta = 0
173
+ h += 1
174
+ end
175
+ }
176
+
177
+ delta += 1
178
+ n += 1
122
179
  end
123
- delta += (m - n) * (h + 1)
124
- n = m
125
180
 
126
- input.each { |cp|
127
- # AMC-ACE-Z can use this simplified version instead
128
- if cp < n && (delta += 1) == 0
129
- raise BufferOverflowError
181
+ output
182
+ end
183
+
184
+ # Encode a hostname using IDN/Punycode algorithms
185
+ def encode_hostname(hostname)
186
+ hostname.match(RE_NONBASIC) or return hostname
187
+
188
+ hostname.split('.').map { |name|
189
+ if name.match(RE_NONBASIC)
190
+ 'xn--' << encode(name)
191
+ else
192
+ name
130
193
  end
194
+ }.join('.')
195
+ end
131
196
 
132
- if cp == n
133
- # Represent delta as a generalized variable-length integer
134
- q = delta
135
- k = BASE
136
- loop {
137
- t = k <= bias ? TMIN : k - bias >= TMAX ? TMAX : k - bias;
138
- break if q < t
139
- output << encode_digit(t + (q - t) % (BASE - t), false)
140
- q = (q - t) / (BASE - t)
141
- k += BASE
142
- }
143
-
144
- output << encode_digit(q, false)
145
-
146
- # Adapt the bias
147
- delta = h == b ? delta / DAMP : delta >> 1
148
- delta += delta / (h + 1)
149
- bias = 0
150
- while delta > CUTOFF
151
- delta /= LOBASE
152
- bias += BASE
153
- end
154
- bias += (LOBASE + 1) * delta / (delta + SKEW)
197
+ # Decode a +string+ encoded in Punycode
198
+ def decode(string)
199
+ # Initialize the state
200
+ n = INITIAL_N
201
+ i = 0
202
+ bias = INITIAL_BIAS
203
+
204
+ if j = string.rindex(DELIMITER)
205
+ b = string[0...j]
206
+
207
+ b.match(RE_NONBASIC) and
208
+ raise ArgumentError, "Illegal character is found in basic part: #{string.inspect}"
209
+
210
+ # Handle the basic code points
211
+
212
+ output = b.unpack('U*')
213
+ u = string[(j + 1)..-1]
214
+ else
215
+ output = []
216
+ u = string
217
+ end
218
+
219
+ # Main decoding loop: Start just after the last delimiter if any
220
+ # basic code points were copied; start at the beginning
221
+ # otherwise.
222
+
223
+ input = u.unpack('C*')
224
+ input_length = input.length
225
+ h = 0
226
+ out = output.length
227
+
228
+ while h < input_length
229
+ # Decode a generalized variable-length integer into delta,
230
+ # which gets added to i. The overflow checking is easier
231
+ # if we increase i as we go, then subtract off its starting
232
+ # value at the end to obtain delta.
233
+
234
+ oldi = i
235
+ w = 1
236
+ k = BASE
155
237
 
156
- delta = 0
238
+ loop {
239
+ digit = decode_digit(input[h]) or
240
+ raise ArgumentError, "Illegal character is found in non-basic part: #{string.inspect}"
157
241
  h += 1
242
+ i += digit * w
243
+ raise BufferOverflowError if i > MAXINT
244
+ t = k <= bias ? TMIN : k - bias >= TMAX ? TMAX : k - bias
245
+ break if digit < t
246
+ w *= BASE - t
247
+ raise BufferOverflowError if w > MAXINT
248
+ k += BASE
249
+ h < input_length or raise ArgumentError, "Malformed input given: #{string.inspect}"
250
+ }
251
+
252
+ # Adapt the bias
253
+ delta = oldi == 0 ? i / DAMP : (i - oldi) >> 1
254
+ delta += delta / (out + 1)
255
+ bias = 0
256
+ while delta > CUTOFF
257
+ delta /= LOBASE
258
+ bias += BASE
158
259
  end
159
- }
260
+ bias += (LOBASE + 1) * delta / (delta + SKEW)
160
261
 
161
- delta += 1
162
- n += 1
163
- end
262
+ # i was supposed to wrap around from out+1 to 0, incrementing
263
+ # n each time, so we'll fix that now:
164
264
 
165
- output
166
- end
167
- module_function :encode
265
+ q, i = i.divmod(out + 1)
266
+ n += q
267
+ raise BufferOverflowError if n > MAXINT
168
268
 
169
- def encode_hostname(hostname)
170
- hostname.match(/[^\x00-\x7f]/) or return hostname
269
+ # Insert n at position i of the output:
171
270
 
172
- hostname.split('.').map { |name|
173
- if name.match(/[^\x00-\x7f]/)
174
- 'xn--' << encode(name)
175
- else
176
- name
271
+ output[i, 0] = n
272
+
273
+ out += 1
274
+ i += 1
177
275
  end
178
- }.join('.')
276
+ output.pack('U*')
277
+ end
278
+
279
+ # Decode a hostname using IDN/Punycode algorithms
280
+ def decode_hostname(hostname)
281
+ hostname.gsub(/(\A|\.)xn--([^.]*)/) {
282
+ $1 << decode($2)
283
+ }
284
+ end
179
285
  end
180
- module_function :encode_hostname
181
286
  end
182
287
  end
@@ -91,6 +91,7 @@ class TestDomainName < Test::Unit::TestCase
91
91
  '-> $1.00 <--']
92
92
  ].each { |title, cps, punycode|
93
93
  assert_equal punycode, DomainName::Punycode.encode(cps.pack('U*')), title
94
+ assert_equal cps.pack('U*').to_nfc, DomainName::Punycode.decode(punycode), title
94
95
  }
95
96
  end
96
97
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: domain_name
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.5.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-18 00:00:00.000000000 Z
12
+ date: 2012-04-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: unf
16
- requirement: &70324603442080 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: 0.0.3
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70324603442080
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.0.3
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: shoulda
27
- requirement: &70324603441520 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ! '>='
@@ -32,21 +37,31 @@ dependencies:
32
37
  version: '0'
33
38
  type: :development
34
39
  prerelease: false
35
- version_requirements: *70324603441520
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: bundler
38
- requirement: &70324603440960 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ~>
42
52
  - !ruby/object:Gem::Version
43
- version: 1.0.0
53
+ version: 1.1.0
44
54
  type: :development
45
55
  prerelease: false
46
- version_requirements: *70324603440960
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.1.0
47
62
  - !ruby/object:Gem::Dependency
48
63
  name: jeweler
49
- requirement: &70324603440180 !ruby/object:Gem::Requirement
64
+ requirement: !ruby/object:Gem::Requirement
50
65
  none: false
51
66
  requirements:
52
67
  - - ~>
@@ -54,21 +69,15 @@ dependencies:
54
69
  version: 1.6.4
55
70
  type: :development
56
71
  prerelease: false
57
- version_requirements: *70324603440180
58
- - !ruby/object:Gem::Dependency
59
- name: rcov
60
- requirement: &70324603439500 !ruby/object:Gem::Requirement
72
+ version_requirements: !ruby/object:Gem::Requirement
61
73
  none: false
62
74
  requirements:
63
- - - ! '>='
75
+ - - ~>
64
76
  - !ruby/object:Gem::Version
65
- version: '0'
66
- type: :development
67
- prerelease: false
68
- version_requirements: *70324603439500
77
+ version: 1.6.4
69
78
  - !ruby/object:Gem::Dependency
70
79
  name: rdoc
71
- requirement: &70324603438960 !ruby/object:Gem::Requirement
80
+ requirement: !ruby/object:Gem::Requirement
72
81
  none: false
73
82
  requirements:
74
83
  - - ! '>='
@@ -76,7 +85,12 @@ dependencies:
76
85
  version: 2.4.2
77
86
  type: :development
78
87
  prerelease: false
79
- version_requirements: *70324603438960
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: 2.4.2
80
94
  description: ! 'This is a Domain Name manipulation library for Ruby.
81
95
 
82
96
 
@@ -123,7 +137,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
123
137
  version: '0'
124
138
  segments:
125
139
  - 0
126
- hash: 79833043846430816
140
+ hash: -1258501941076469497
127
141
  required_rubygems_version: !ruby/object:Gem::Requirement
128
142
  none: false
129
143
  requirements:
@@ -132,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
146
  version: '0'
133
147
  requirements: []
134
148
  rubyforge_project:
135
- rubygems_version: 1.8.11
149
+ rubygems_version: 1.8.21
136
150
  signing_key:
137
151
  specification_version: 3
138
152
  summary: Domain Name manipulation library for Ruby