rack 1.6.13 → 2.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack might be problematic. Click here for more details.

Files changed (138) hide show
  1. checksums.yaml +5 -5
  2. data/HISTORY.md +139 -18
  3. data/README.rdoc +17 -25
  4. data/Rakefile +6 -14
  5. data/SPEC +8 -9
  6. data/contrib/rack_logo.svg +164 -111
  7. data/lib/rack.rb +70 -21
  8. data/lib/rack/auth/digest/request.rb +1 -1
  9. data/lib/rack/body_proxy.rb +14 -9
  10. data/lib/rack/builder.rb +3 -3
  11. data/lib/rack/chunked.rb +5 -5
  12. data/lib/rack/{commonlogger.rb → common_logger.rb} +2 -2
  13. data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
  14. data/lib/rack/content_length.rb +2 -2
  15. data/lib/rack/deflater.rb +4 -4
  16. data/lib/rack/directory.rb +49 -55
  17. data/lib/rack/etag.rb +2 -1
  18. data/lib/rack/events.rb +154 -0
  19. data/lib/rack/file.rb +55 -40
  20. data/lib/rack/handler.rb +2 -24
  21. data/lib/rack/handler/cgi.rb +15 -16
  22. data/lib/rack/handler/fastcgi.rb +13 -14
  23. data/lib/rack/handler/lsws.rb +11 -11
  24. data/lib/rack/handler/scgi.rb +15 -15
  25. data/lib/rack/handler/thin.rb +3 -0
  26. data/lib/rack/handler/webrick.rb +22 -24
  27. data/lib/rack/head.rb +15 -17
  28. data/lib/rack/lint.rb +38 -38
  29. data/lib/rack/lobster.rb +1 -1
  30. data/lib/rack/lock.rb +6 -10
  31. data/lib/rack/logger.rb +2 -2
  32. data/lib/rack/media_type.rb +38 -0
  33. data/lib/rack/{methodoverride.rb → method_override.rb} +4 -11
  34. data/lib/rack/mime.rb +18 -5
  35. data/lib/rack/mock.rb +35 -52
  36. data/lib/rack/multipart.rb +35 -6
  37. data/lib/rack/multipart/generator.rb +4 -4
  38. data/lib/rack/multipart/parser.rb +273 -158
  39. data/lib/rack/multipart/uploaded_file.rb +1 -2
  40. data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
  41. data/lib/rack/query_parser.rb +174 -0
  42. data/lib/rack/recursive.rb +8 -8
  43. data/lib/rack/reloader.rb +1 -2
  44. data/lib/rack/request.rb +370 -304
  45. data/lib/rack/response.rb +129 -56
  46. data/lib/rack/rewindable_input.rb +1 -12
  47. data/lib/rack/runtime.rb +10 -18
  48. data/lib/rack/sendfile.rb +5 -7
  49. data/lib/rack/server.rb +31 -25
  50. data/lib/rack/session/abstract/id.rb +93 -135
  51. data/lib/rack/session/cookie.rb +26 -28
  52. data/lib/rack/session/memcache.rb +8 -14
  53. data/lib/rack/session/pool.rb +14 -21
  54. data/lib/rack/show_exceptions.rb +386 -0
  55. data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
  56. data/lib/rack/static.rb +30 -5
  57. data/lib/rack/tempfile_reaper.rb +2 -2
  58. data/lib/rack/urlmap.rb +13 -14
  59. data/lib/rack/utils.rb +128 -221
  60. data/rack.gemspec +9 -5
  61. data/test/builder/an_underscore_app.rb +5 -0
  62. data/test/builder/options.ru +1 -1
  63. data/test/cgi/test.fcgi +1 -0
  64. data/test/cgi/test.gz +0 -0
  65. data/test/helper.rb +31 -0
  66. data/test/multipart/filename_with_encoded_words +7 -0
  67. data/test/multipart/{filename_with_null_byte → filename_with_single_quote} +1 -1
  68. data/test/multipart/quoted +15 -0
  69. data/test/multipart/rack-logo.png +0 -0
  70. data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
  71. data/test/spec_auth_basic.rb +20 -19
  72. data/test/spec_auth_digest.rb +47 -46
  73. data/test/spec_body_proxy.rb +27 -27
  74. data/test/spec_builder.rb +51 -41
  75. data/test/spec_cascade.rb +24 -22
  76. data/test/spec_cgi.rb +49 -67
  77. data/test/spec_chunked.rb +36 -34
  78. data/test/{spec_commonlogger.rb → spec_common_logger.rb} +23 -21
  79. data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
  80. data/test/spec_config.rb +3 -2
  81. data/test/spec_content_length.rb +18 -17
  82. data/test/spec_content_type.rb +13 -12
  83. data/test/spec_deflater.rb +66 -40
  84. data/test/spec_directory.rb +72 -27
  85. data/test/spec_etag.rb +32 -31
  86. data/test/spec_events.rb +133 -0
  87. data/test/spec_fastcgi.rb +50 -72
  88. data/test/spec_file.rb +96 -77
  89. data/test/spec_handler.rb +19 -34
  90. data/test/spec_head.rb +15 -14
  91. data/test/spec_lint.rb +162 -197
  92. data/test/spec_lobster.rb +24 -23
  93. data/test/spec_lock.rb +69 -39
  94. data/test/spec_logger.rb +4 -3
  95. data/test/spec_media_type.rb +42 -0
  96. data/test/spec_method_override.rb +83 -0
  97. data/test/spec_mime.rb +19 -19
  98. data/test/spec_mock.rb +196 -151
  99. data/test/spec_multipart.rb +310 -202
  100. data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
  101. data/test/spec_recursive.rb +17 -14
  102. data/test/spec_request.rb +763 -607
  103. data/test/spec_response.rb +209 -156
  104. data/test/spec_rewindable_input.rb +50 -40
  105. data/test/spec_runtime.rb +11 -10
  106. data/test/spec_sendfile.rb +30 -35
  107. data/test/spec_server.rb +78 -52
  108. data/test/spec_session_abstract_id.rb +11 -33
  109. data/test/spec_session_cookie.rb +97 -65
  110. data/test/spec_session_memcache.rb +63 -101
  111. data/test/spec_session_pool.rb +48 -84
  112. data/test/spec_show_exceptions.rb +80 -0
  113. data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
  114. data/test/spec_static.rb +71 -32
  115. data/test/spec_tempfile_reaper.rb +11 -10
  116. data/test/spec_thin.rb +55 -50
  117. data/test/spec_urlmap.rb +79 -78
  118. data/test/spec_utils.rb +417 -345
  119. data/test/spec_version.rb +2 -8
  120. data/test/spec_webrick.rb +77 -67
  121. data/test/static/foo.html +1 -0
  122. data/test/testrequest.rb +1 -1
  123. data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
  124. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
  125. metadata +116 -71
  126. data/KNOWN-ISSUES +0 -44
  127. data/lib/rack/backports/uri/common_18.rb +0 -56
  128. data/lib/rack/backports/uri/common_192.rb +0 -52
  129. data/lib/rack/backports/uri/common_193.rb +0 -29
  130. data/lib/rack/handler/evented_mongrel.rb +0 -8
  131. data/lib/rack/handler/mongrel.rb +0 -106
  132. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  133. data/lib/rack/showexceptions.rb +0 -387
  134. data/lib/rack/utils/okjson.rb +0 -600
  135. data/test/spec_methodoverride.rb +0 -111
  136. data/test/spec_mongrel.rb +0 -182
  137. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  138. data/test/spec_showexceptions.rb +0 -98
@@ -1,600 +0,0 @@
1
- # encoding: UTF-8
2
- #
3
- # Copyright 2011, 2012 Keith Rarick
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
-
23
- # See https://github.com/kr/okjson for updates.
24
-
25
- require 'stringio'
26
-
27
- # Some parts adapted from
28
- # https://golang.org/src/encoding/json/decode.go and
29
- # https://golang.org/src/unicode/utf8/utf8.go
30
- module Rack::Utils::OkJson
31
- Upstream = '43'
32
- extend self
33
-
34
-
35
- # Decodes a json document in string s and
36
- # returns the corresponding ruby value.
37
- # String s must be valid UTF-8. If you have
38
- # a string in some other encoding, convert
39
- # it first.
40
- #
41
- # String values in the resulting structure
42
- # will be UTF-8.
43
- def decode(s)
44
- ts = lex(s)
45
- v, ts = textparse(ts)
46
- if ts.length > 0
47
- raise Error, 'trailing garbage'
48
- end
49
- v
50
- end
51
-
52
-
53
- # Encodes x into a json text. It may contain only
54
- # Array, Hash, String, Numeric, true, false, nil.
55
- # (Note, this list excludes Symbol.)
56
- # X itself must be an Array or a Hash.
57
- # No other value can be encoded, and an error will
58
- # be raised if x contains any other value, such as
59
- # Nan, Infinity, Symbol, and Proc, or if a Hash key
60
- # is not a String.
61
- # Strings contained in x must be valid UTF-8.
62
- def encode(x)
63
- case x
64
- when Hash then objenc(x)
65
- when Array then arrenc(x)
66
- else
67
- raise Error, 'root value must be an Array or a Hash'
68
- end
69
- end
70
-
71
-
72
- def valenc(x)
73
- case x
74
- when Hash then objenc(x)
75
- when Array then arrenc(x)
76
- when String then strenc(x)
77
- when Numeric then numenc(x)
78
- when true then "true"
79
- when false then "false"
80
- when nil then "null"
81
- else
82
- raise Error, "cannot encode #{x.class}: #{x.inspect}"
83
- end
84
- end
85
-
86
-
87
- private
88
-
89
-
90
- # Parses a "json text" in the sense of RFC 4627.
91
- # Returns the parsed value and any trailing tokens.
92
- # Note: this is almost the same as valparse,
93
- # except that it does not accept atomic values.
94
- def textparse(ts)
95
- if ts.length <= 0
96
- raise Error, 'empty'
97
- end
98
-
99
- typ, _, val = ts[0]
100
- case typ
101
- when '{' then objparse(ts)
102
- when '[' then arrparse(ts)
103
- else
104
- raise Error, "unexpected #{val.inspect}"
105
- end
106
- end
107
-
108
-
109
- # Parses a "value" in the sense of RFC 4627.
110
- # Returns the parsed value and any trailing tokens.
111
- def valparse(ts)
112
- if ts.length <= 0
113
- raise Error, 'empty'
114
- end
115
-
116
- typ, _, val = ts[0]
117
- case typ
118
- when '{' then objparse(ts)
119
- when '[' then arrparse(ts)
120
- when :val,:str then [val, ts[1..-1]]
121
- else
122
- raise Error, "unexpected #{val.inspect}"
123
- end
124
- end
125
-
126
-
127
- # Parses an "object" in the sense of RFC 4627.
128
- # Returns the parsed value and any trailing tokens.
129
- def objparse(ts)
130
- ts = eat('{', ts)
131
- obj = {}
132
-
133
- if ts[0][0] == '}'
134
- return obj, ts[1..-1]
135
- end
136
-
137
- k, v, ts = pairparse(ts)
138
- obj[k] = v
139
-
140
- if ts[0][0] == '}'
141
- return obj, ts[1..-1]
142
- end
143
-
144
- loop do
145
- ts = eat(',', ts)
146
-
147
- k, v, ts = pairparse(ts)
148
- obj[k] = v
149
-
150
- if ts[0][0] == '}'
151
- return obj, ts[1..-1]
152
- end
153
- end
154
- end
155
-
156
-
157
- # Parses a "member" in the sense of RFC 4627.
158
- # Returns the parsed values and any trailing tokens.
159
- def pairparse(ts)
160
- (typ, _, k), ts = ts[0], ts[1..-1]
161
- if typ != :str
162
- raise Error, "unexpected #{k.inspect}"
163
- end
164
- ts = eat(':', ts)
165
- v, ts = valparse(ts)
166
- [k, v, ts]
167
- end
168
-
169
-
170
- # Parses an "array" in the sense of RFC 4627.
171
- # Returns the parsed value and any trailing tokens.
172
- def arrparse(ts)
173
- ts = eat('[', ts)
174
- arr = []
175
-
176
- if ts[0][0] == ']'
177
- return arr, ts[1..-1]
178
- end
179
-
180
- v, ts = valparse(ts)
181
- arr << v
182
-
183
- if ts[0][0] == ']'
184
- return arr, ts[1..-1]
185
- end
186
-
187
- loop do
188
- ts = eat(',', ts)
189
-
190
- v, ts = valparse(ts)
191
- arr << v
192
-
193
- if ts[0][0] == ']'
194
- return arr, ts[1..-1]
195
- end
196
- end
197
- end
198
-
199
-
200
- def eat(typ, ts)
201
- if ts[0][0] != typ
202
- raise Error, "expected #{typ} (got #{ts[0].inspect})"
203
- end
204
- ts[1..-1]
205
- end
206
-
207
-
208
- # Scans s and returns a list of json tokens,
209
- # excluding white space (as defined in RFC 4627).
210
- def lex(s)
211
- ts = []
212
- while s.length > 0
213
- typ, lexeme, val = tok(s)
214
- if typ == nil
215
- raise Error, "invalid character at #{s[0,10].inspect}"
216
- end
217
- if typ != :space
218
- ts << [typ, lexeme, val]
219
- end
220
- s = s[lexeme.length..-1]
221
- end
222
- ts
223
- end
224
-
225
-
226
- # Scans the first token in s and
227
- # returns a 3-element list, or nil
228
- # if s does not begin with a valid token.
229
- #
230
- # The first list element is one of
231
- # '{', '}', ':', ',', '[', ']',
232
- # :val, :str, and :space.
233
- #
234
- # The second element is the lexeme.
235
- #
236
- # The third element is the value of the
237
- # token for :val and :str, otherwise
238
- # it is the lexeme.
239
- def tok(s)
240
- case s[0]
241
- when ?{ then ['{', s[0,1], s[0,1]]
242
- when ?} then ['}', s[0,1], s[0,1]]
243
- when ?: then [':', s[0,1], s[0,1]]
244
- when ?, then [',', s[0,1], s[0,1]]
245
- when ?[ then ['[', s[0,1], s[0,1]]
246
- when ?] then [']', s[0,1], s[0,1]]
247
- when ?n then nulltok(s)
248
- when ?t then truetok(s)
249
- when ?f then falsetok(s)
250
- when ?" then strtok(s)
251
- when Spc, ?\t, ?\n, ?\r then [:space, s[0,1], s[0,1]]
252
- else
253
- numtok(s)
254
- end
255
- end
256
-
257
-
258
- def nulltok(s); s[0,4] == 'null' ? [:val, 'null', nil] : [] end
259
- def truetok(s); s[0,4] == 'true' ? [:val, 'true', true] : [] end
260
- def falsetok(s); s[0,5] == 'false' ? [:val, 'false', false] : [] end
261
-
262
-
263
- def numtok(s)
264
- m = /-?([1-9][0-9]+|[0-9])([.][0-9]+)?([eE][+-]?[0-9]+)?/.match(s)
265
- if m && m.begin(0) == 0
266
- if !m[2] && !m[3]
267
- [:val, m[0], Integer(m[0])]
268
- elsif m[2]
269
- [:val, m[0], Float(m[0])]
270
- else
271
- [:val, m[0], Integer(m[1])*(10**m[3][1..-1].to_i(10))]
272
- end
273
- else
274
- []
275
- end
276
- end
277
-
278
-
279
- def strtok(s)
280
- m = /"([^"\\]|\\["\/\\bfnrt]|\\u[0-9a-fA-F]{4})*"/.match(s)
281
- if ! m
282
- raise Error, "invalid string literal at #{abbrev(s)}"
283
- end
284
- [:str, m[0], unquote(m[0])]
285
- end
286
-
287
-
288
- def abbrev(s)
289
- t = s[0,10]
290
- p = t['`']
291
- t = t[0,p] if p
292
- t = t + '...' if t.length < s.length
293
- '`' + t + '`'
294
- end
295
-
296
-
297
- # Converts a quoted json string literal q into a UTF-8-encoded string.
298
- # The rules are different than for Ruby, so we cannot use eval.
299
- # Unquote will raise an error if q contains control characters.
300
- def unquote(q)
301
- q = q[1...-1]
302
- a = q.dup # allocate a big enough string
303
- # In ruby >= 1.9, a[w] is a codepoint, not a byte.
304
- if rubydoesenc?
305
- a.force_encoding('UTF-8')
306
- end
307
- r, w = 0, 0
308
- while r < q.length
309
- c = q[r]
310
- if c == ?\\
311
- r += 1
312
- if r >= q.length
313
- raise Error, "string literal ends with a \"\\\": \"#{q}\""
314
- end
315
-
316
- case q[r]
317
- when ?",?\\,?/,?'
318
- a[w] = q[r]
319
- r += 1
320
- w += 1
321
- when ?b,?f,?n,?r,?t
322
- a[w] = Unesc[q[r]]
323
- r += 1
324
- w += 1
325
- when ?u
326
- r += 1
327
- uchar = begin
328
- hexdec4(q[r,4])
329
- rescue RuntimeError => e
330
- raise Error, "invalid escape sequence \\u#{q[r,4]}: #{e}"
331
- end
332
- r += 4
333
- if surrogate? uchar
334
- if q.length >= r+6
335
- uchar1 = hexdec4(q[r+2,4])
336
- uchar = subst(uchar, uchar1)
337
- if uchar != Ucharerr
338
- # A valid pair; consume.
339
- r += 6
340
- end
341
- end
342
- end
343
- if rubydoesenc?
344
- a[w] = '' << uchar
345
- w += 1
346
- else
347
- w += ucharenc(a, w, uchar)
348
- end
349
- else
350
- raise Error, "invalid escape char #{q[r]} in \"#{q}\""
351
- end
352
- elsif c == ?" || c < Spc
353
- raise Error, "invalid character in string literal \"#{q}\""
354
- else
355
- # Copy anything else byte-for-byte.
356
- # Valid UTF-8 will remain valid UTF-8.
357
- # Invalid UTF-8 will remain invalid UTF-8.
358
- # In ruby >= 1.9, c is a codepoint, not a byte,
359
- # in which case this is still what we want.
360
- a[w] = c
361
- r += 1
362
- w += 1
363
- end
364
- end
365
- a[0,w]
366
- end
367
-
368
-
369
- # Encodes unicode character u as UTF-8
370
- # bytes in string a at position i.
371
- # Returns the number of bytes written.
372
- def ucharenc(a, i, u)
373
- if u <= Uchar1max
374
- a[i] = (u & 0xff).chr
375
- 1
376
- elsif u <= Uchar2max
377
- a[i+0] = (Utag2 | ((u>>6)&0xff)).chr
378
- a[i+1] = (Utagx | (u&Umaskx)).chr
379
- 2
380
- elsif u <= Uchar3max
381
- a[i+0] = (Utag3 | ((u>>12)&0xff)).chr
382
- a[i+1] = (Utagx | ((u>>6)&Umaskx)).chr
383
- a[i+2] = (Utagx | (u&Umaskx)).chr
384
- 3
385
- else
386
- a[i+0] = (Utag4 | ((u>>18)&0xff)).chr
387
- a[i+1] = (Utagx | ((u>>12)&Umaskx)).chr
388
- a[i+2] = (Utagx | ((u>>6)&Umaskx)).chr
389
- a[i+3] = (Utagx | (u&Umaskx)).chr
390
- 4
391
- end
392
- end
393
-
394
-
395
- def hexdec4(s)
396
- if s.length != 4
397
- raise Error, 'short'
398
- end
399
- (nibble(s[0])<<12) | (nibble(s[1])<<8) | (nibble(s[2])<<4) | nibble(s[3])
400
- end
401
-
402
-
403
- def subst(u1, u2)
404
- if Usurr1 <= u1 && u1 < Usurr2 && Usurr2 <= u2 && u2 < Usurr3
405
- return ((u1-Usurr1)<<10) | (u2-Usurr2) + Usurrself
406
- end
407
- return Ucharerr
408
- end
409
-
410
-
411
- def surrogate?(u)
412
- Usurr1 <= u && u < Usurr3
413
- end
414
-
415
-
416
- def nibble(c)
417
- if ?0 <= c && c <= ?9 then c.ord - ?0.ord
418
- elsif ?a <= c && c <= ?z then c.ord - ?a.ord + 10
419
- elsif ?A <= c && c <= ?Z then c.ord - ?A.ord + 10
420
- else
421
- raise Error, "invalid hex code #{c}"
422
- end
423
- end
424
-
425
-
426
- def objenc(x)
427
- '{' + x.map{|k,v| keyenc(k) + ':' + valenc(v)}.join(',') + '}'
428
- end
429
-
430
-
431
- def arrenc(a)
432
- '[' + a.map{|x| valenc(x)}.join(',') + ']'
433
- end
434
-
435
-
436
- def keyenc(k)
437
- case k
438
- when String then strenc(k)
439
- else
440
- raise Error, "Hash key is not a string: #{k.inspect}"
441
- end
442
- end
443
-
444
-
445
- def strenc(s)
446
- t = StringIO.new
447
- t.putc(?")
448
- r = 0
449
-
450
- while r < s.length
451
- case s[r]
452
- when ?" then t.print('\\"')
453
- when ?\\ then t.print('\\\\')
454
- when ?\b then t.print('\\b')
455
- when ?\f then t.print('\\f')
456
- when ?\n then t.print('\\n')
457
- when ?\r then t.print('\\r')
458
- when ?\t then t.print('\\t')
459
- else
460
- c = s[r]
461
- # In ruby >= 1.9, s[r] is a codepoint, not a byte.
462
- if rubydoesenc?
463
- begin
464
- # c.ord will raise an error if c is invalid UTF-8
465
- if c.ord < Spc.ord
466
- c = "\\u%04x" % [c.ord]
467
- end
468
- t.write(c)
469
- rescue
470
- t.write(Ustrerr)
471
- end
472
- elsif c < Spc
473
- t.write("\\u%04x" % c)
474
- elsif Spc <= c && c <= ?~
475
- t.putc(c)
476
- else
477
- n = ucharcopy(t, s, r) # ensure valid UTF-8 output
478
- r += n - 1 # r is incremented below
479
- end
480
- end
481
- r += 1
482
- end
483
- t.putc(?")
484
- t.string
485
- end
486
-
487
-
488
- def numenc(x)
489
- if ((x.nan? || x.infinite?) rescue false)
490
- raise Error, "Numeric cannot be represented: #{x}"
491
- end
492
- "#{x}"
493
- end
494
-
495
-
496
- # Copies the valid UTF-8 bytes of a single character
497
- # from string s at position i to I/O object t, and
498
- # returns the number of bytes copied.
499
- # If no valid UTF-8 char exists at position i,
500
- # ucharcopy writes Ustrerr and returns 1.
501
- def ucharcopy(t, s, i)
502
- n = s.length - i
503
- raise Utf8Error if n < 1
504
-
505
- c0 = s[i].ord
506
-
507
- # 1-byte, 7-bit sequence?
508
- if c0 < Utagx
509
- t.putc(c0)
510
- return 1
511
- end
512
-
513
- raise Utf8Error if c0 < Utag2 # unexpected continuation byte?
514
-
515
- raise Utf8Error if n < 2 # need continuation byte
516
- c1 = s[i+1].ord
517
- raise Utf8Error if c1 < Utagx || Utag2 <= c1
518
-
519
- # 2-byte, 11-bit sequence?
520
- if c0 < Utag3
521
- raise Utf8Error if ((c0&Umask2)<<6 | (c1&Umaskx)) <= Uchar1max
522
- t.putc(c0)
523
- t.putc(c1)
524
- return 2
525
- end
526
-
527
- # need second continuation byte
528
- raise Utf8Error if n < 3
529
-
530
- c2 = s[i+2].ord
531
- raise Utf8Error if c2 < Utagx || Utag2 <= c2
532
-
533
- # 3-byte, 16-bit sequence?
534
- if c0 < Utag4
535
- u = (c0&Umask3)<<12 | (c1&Umaskx)<<6 | (c2&Umaskx)
536
- raise Utf8Error if u <= Uchar2max
537
- t.putc(c0)
538
- t.putc(c1)
539
- t.putc(c2)
540
- return 3
541
- end
542
-
543
- # need third continuation byte
544
- raise Utf8Error if n < 4
545
- c3 = s[i+3].ord
546
- raise Utf8Error if c3 < Utagx || Utag2 <= c3
547
-
548
- # 4-byte, 21-bit sequence?
549
- if c0 < Utag5
550
- u = (c0&Umask4)<<18 | (c1&Umaskx)<<12 | (c2&Umaskx)<<6 | (c3&Umaskx)
551
- raise Utf8Error if u <= Uchar3max
552
- t.putc(c0)
553
- t.putc(c1)
554
- t.putc(c2)
555
- t.putc(c3)
556
- return 4
557
- end
558
-
559
- raise Utf8Error
560
- rescue Utf8Error
561
- t.write(Ustrerr)
562
- return 1
563
- end
564
-
565
-
566
- def rubydoesenc?
567
- ::String.method_defined?(:force_encoding)
568
- end
569
-
570
-
571
- class Utf8Error < ::StandardError
572
- end
573
-
574
-
575
- class Error < ::StandardError
576
- end
577
-
578
-
579
- Utagx = 0b1000_0000
580
- Utag2 = 0b1100_0000
581
- Utag3 = 0b1110_0000
582
- Utag4 = 0b1111_0000
583
- Utag5 = 0b1111_1000
584
- Umaskx = 0b0011_1111
585
- Umask2 = 0b0001_1111
586
- Umask3 = 0b0000_1111
587
- Umask4 = 0b0000_0111
588
- Uchar1max = (1<<7) - 1
589
- Uchar2max = (1<<11) - 1
590
- Uchar3max = (1<<16) - 1
591
- Ucharerr = 0xFFFD # unicode "replacement char"
592
- Ustrerr = "\xef\xbf\xbd" # unicode "replacement char"
593
- Usurrself = 0x10000
594
- Usurr1 = 0xd800
595
- Usurr2 = 0xdc00
596
- Usurr3 = 0xe000
597
-
598
- Spc = ' '[0]
599
- Unesc = {?b=>?\b, ?f=>?\f, ?n=>?\n, ?r=>?\r, ?t=>?\t}
600
- end