sentry-raven 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,614 +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
- # http://golang.org/src/pkg/json/decode.go and
29
- # http://golang.org/src/pkg/utf8/utf8.go
30
- module Raven
31
- module OkJson
32
- Upstream = '43'
33
- extend self
34
-
35
-
36
- # Decodes a json document in string s and
37
- # returns the corresponding ruby value.
38
- # String s must be valid UTF-8. If you have
39
- # a string in some other encoding, convert
40
- # it first.
41
- #
42
- # String values in the resulting structure
43
- # will be UTF-8.
44
- def decode(s)
45
- ts = lex(s)
46
- v, ts = textparse(ts)
47
- if ts.length > 0
48
- raise Error, 'trailing garbage'
49
- end
50
- v
51
- end
52
-
53
-
54
- # Encodes x into a json text. It may contain only
55
- # Array, Hash, String, Numeric, true, false, nil.
56
- # (Note, this list excludes Symbol.)
57
- # X itself must be an Array or a Hash.
58
- # No other value can be encoded, and an error will
59
- # be raised if x contains any other value, such as
60
- # Nan, Infinity, Symbol, and Proc, or if a Hash key
61
- # is not a String.
62
- # Strings contained in x must be valid UTF-8.
63
- def encode(x)
64
- case x
65
- when Hash then objenc(x)
66
- when Array then arrenc(x)
67
- else
68
- raise Error, 'root value must be an Array or a Hash'
69
- end
70
- end
71
-
72
-
73
- def valenc(x)
74
- case x
75
- when Hash then objenc(x)
76
- when Array then arrenc(x)
77
- when String then strenc(x)
78
- when Symbol then strenc(x.to_s)
79
- when Numeric then numenc(x)
80
- when true then "true"
81
- when false then "false"
82
- when nil then "null"
83
- else
84
- strenc((x.inspect rescue $!.to_s))
85
- end
86
- end
87
-
88
-
89
- private
90
-
91
-
92
- # Parses a "json text" in the sense of RFC 4627.
93
- # Returns the parsed value and any trailing tokens.
94
- # Note: this is almost the same as valparse,
95
- # except that it does not accept atomic values.
96
- def textparse(ts)
97
- if ts.length <= 0
98
- raise Error, 'empty'
99
- end
100
-
101
- typ, _, val = ts[0]
102
- case typ
103
- when '{' then objparse(ts)
104
- when '[' then arrparse(ts)
105
- else
106
- raise Error, "unexpected #{val.inspect}"
107
- end
108
- end
109
-
110
-
111
- # Parses a "value" in the sense of RFC 4627.
112
- # Returns the parsed value and any trailing tokens.
113
- def valparse(ts)
114
- if ts.length <= 0
115
- raise Error, 'empty'
116
- end
117
-
118
- typ, _, val = ts[0]
119
- case typ
120
- when '{' then objparse(ts)
121
- when '[' then arrparse(ts)
122
- when :val,:str then [val, ts[1..-1]]
123
- else
124
- raise Error, "unexpected #{val.inspect}"
125
- end
126
- end
127
-
128
-
129
- # Parses an "object" in the sense of RFC 4627.
130
- # Returns the parsed value and any trailing tokens.
131
- def objparse(ts)
132
- ts = eat('{', ts)
133
- obj = {}
134
-
135
- unless ts[0]
136
- raise Error, "unexpected end of object"
137
- end
138
-
139
- if ts[0][0] == '}'
140
- return obj, ts[1..-1]
141
- end
142
-
143
- k, v, ts = pairparse(ts)
144
- obj[k] = v
145
-
146
- if ts[0][0] == '}'
147
- return obj, ts[1..-1]
148
- end
149
-
150
- loop do
151
- ts = eat(',', ts)
152
-
153
- k, v, ts = pairparse(ts)
154
- obj[k] = v
155
-
156
- if ts[0][0] == '}'
157
- return obj, ts[1..-1]
158
- end
159
- end
160
- end
161
-
162
-
163
- # Parses a "member" in the sense of RFC 4627.
164
- # Returns the parsed values and any trailing tokens.
165
- def pairparse(ts)
166
- (typ, _, k), ts = ts[0], ts[1..-1]
167
- if typ != :str
168
- raise Error, "unexpected #{k.inspect}"
169
- end
170
- ts = eat(':', ts)
171
- v, ts = valparse(ts)
172
- [k, v, ts]
173
- end
174
-
175
-
176
- # Parses an "array" in the sense of RFC 4627.
177
- # Returns the parsed value and any trailing tokens.
178
- def arrparse(ts)
179
- ts = eat('[', ts)
180
- arr = []
181
-
182
- unless ts[0]
183
- raise Error, "unexpected end of array"
184
- end
185
-
186
- if ts[0][0] == ']'
187
- return arr, ts[1..-1]
188
- end
189
-
190
- v, ts = valparse(ts)
191
- arr << v
192
-
193
- if ts[0][0] == ']'
194
- return arr, ts[1..-1]
195
- end
196
-
197
- loop do
198
- ts = eat(',', ts)
199
-
200
- v, ts = valparse(ts)
201
- arr << v
202
-
203
- if ts[0][0] == ']'
204
- return arr, ts[1..-1]
205
- end
206
- end
207
- end
208
-
209
-
210
- def eat(typ, ts)
211
- if ts[0][0] != typ
212
- raise Error, "expected #{typ} (got #{ts[0].inspect})"
213
- end
214
- ts[1..-1]
215
- end
216
-
217
-
218
- # Scans s and returns a list of json tokens,
219
- # excluding white space (as defined in RFC 4627).
220
- def lex(s)
221
- ts = []
222
- while s.length > 0
223
- typ, lexeme, val = tok(s)
224
- if typ.nil?
225
- raise Error, "invalid character at #{s[0,10].inspect}"
226
- end
227
- if typ != :space
228
- ts << [typ, lexeme, val]
229
- end
230
- s = s[lexeme.length..-1]
231
- end
232
- ts
233
- end
234
-
235
-
236
- # Scans the first token in s and
237
- # returns a 3-element list, or nil
238
- # if s does not begin with a valid token.
239
- #
240
- # The first list element is one of
241
- # '{', '}', ':', ',', '[', ']',
242
- # :val, :str, and :space.
243
- #
244
- # The second element is the lexeme.
245
- #
246
- # The third element is the value of the
247
- # token for :val and :str, otherwise
248
- # it is the lexeme.
249
- def tok(s)
250
- case s[0]
251
- when ?{ then ['{', s[0,1], s[0,1]]
252
- when ?} then ['}', s[0,1], s[0,1]]
253
- when ?: then [':', s[0,1], s[0,1]]
254
- when ?, then [',', s[0,1], s[0,1]]
255
- when ?[ then ['[', s[0,1], s[0,1]]
256
- when ?] then [']', s[0,1], s[0,1]]
257
- when ?n then nulltok(s)
258
- when ?t then truetok(s)
259
- when ?f then falsetok(s)
260
- when ?" then strtok(s)
261
- when Spc, ?\t, ?\n, ?\r then [:space, s[0,1], s[0,1]]
262
- else
263
- numtok(s)
264
- end
265
- end
266
-
267
-
268
- def nulltok(s); s[0,4] == 'null' ? [:val, 'null', nil] : [] end
269
- def truetok(s); s[0,4] == 'true' ? [:val, 'true', true] : [] end
270
- def falsetok(s); s[0,5] == 'false' ? [:val, 'false', false] : [] end
271
-
272
-
273
- def numtok(s)
274
- m = /-?([1-9][0-9]+|[0-9])([.][0-9]+)?([eE][+-]?[0-9]+)?/.match(s)
275
- if m && m.begin(0) == 0
276
- if !m[2] && !m[3]
277
- [:val, m[0], Integer(m[0])]
278
- elsif m[2]
279
- [:val, m[0], Float(m[0])]
280
- else
281
- # We don't convert scientific notation
282
- [:val, m[0], m[0]]
283
- end
284
- else
285
- []
286
- end
287
- end
288
-
289
-
290
- def strtok(s)
291
- m = /"([^"\\]|\\["\/\\bfnrt]|\\u[0-9a-fA-F]{4})*"/.match(s)
292
- unless m
293
- raise Error, "invalid string literal at #{abbrev(s)}"
294
- end
295
- [:str, m[0], unquote(m[0])]
296
- end
297
-
298
-
299
- def abbrev(s)
300
- t = s[0,10]
301
- p = t['`']
302
- t = t[0,p] if p
303
- t = t + '...' if t.length < s.length
304
- '`' + t + '`'
305
- end
306
-
307
-
308
- # Converts a quoted json string literal q into a UTF-8-encoded string.
309
- # The rules are different than for Ruby, so we cannot use eval.
310
- # Unquote will raise an error if q contains control characters.
311
- def unquote(q)
312
- q = q[1...-1]
313
- a = q.dup # allocate a big enough string
314
- # In ruby >= 1.9, a[w] is a codepoint, not a byte.
315
- if rubydoesenc?
316
- a.force_encoding('UTF-8')
317
- end
318
- r, w = 0, 0
319
- while r < q.length
320
- c = q[r]
321
- if c == ?\\
322
- r += 1
323
- if r >= q.length
324
- raise Error, "string literal ends with a \"\\\": \"#{q}\""
325
- end
326
-
327
- case q[r]
328
- when ?",?\\,?/,?'
329
- a[w] = q[r]
330
- r += 1
331
- w += 1
332
- when ?b,?f,?n,?r,?t
333
- a[w] = Unesc[q[r]]
334
- r += 1
335
- w += 1
336
- when ?u
337
- r += 1
338
- uchar = begin
339
- hexdec4(q[r,4])
340
- rescue RuntimeError => e
341
- raise Error, "invalid escape sequence \\u#{q[r,4]}: #{e}"
342
- end
343
- r += 4
344
- if surrogate? uchar
345
- if q.length >= r+6
346
- uchar1 = hexdec4(q[r+2,4])
347
- uchar = subst(uchar, uchar1)
348
- if uchar != Ucharerr
349
- # A valid pair; consume.
350
- r += 6
351
- end
352
- end
353
- end
354
- if rubydoesenc?
355
- a[w] = '' << uchar
356
- w += 1
357
- else
358
- w += ucharenc(a, w, uchar)
359
- end
360
- else
361
- raise Error, "invalid escape char #{q[r]} in \"#{q}\""
362
- end
363
- elsif c == ?" || c < Spc
364
- raise Error, "invalid character in string literal \"#{q}\""
365
- else
366
- # Copy anything else byte-for-byte.
367
- # Valid UTF-8 will remain valid UTF-8.
368
- # Invalid UTF-8 will remain invalid UTF-8.
369
- # In ruby >= 1.9, c is a codepoint, not a byte,
370
- # in which case this is still what we want.
371
- a[w] = c
372
- r += 1
373
- w += 1
374
- end
375
- end
376
- a[0,w]
377
- end
378
-
379
-
380
- # Encodes unicode character u as UTF-8
381
- # bytes in string a at position i.
382
- # Returns the number of bytes written.
383
- def ucharenc(a, i, u)
384
- if u <= Uchar1max
385
- a[i] = (u & 0xff).chr
386
- 1
387
- elsif u <= Uchar2max
388
- a[i+0] = (Utag2 | ((u>>6)&0xff)).chr
389
- a[i+1] = (Utagx | (u&Umaskx)).chr
390
- 2
391
- elsif u <= Uchar3max
392
- a[i+0] = (Utag3 | ((u>>12)&0xff)).chr
393
- a[i+1] = (Utagx | ((u>>6)&Umaskx)).chr
394
- a[i+2] = (Utagx | (u&Umaskx)).chr
395
- 3
396
- else
397
- a[i+0] = (Utag4 | ((u>>18)&0xff)).chr
398
- a[i+1] = (Utagx | ((u>>12)&Umaskx)).chr
399
- a[i+2] = (Utagx | ((u>>6)&Umaskx)).chr
400
- a[i+3] = (Utagx | (u&Umaskx)).chr
401
- 4
402
- end
403
- end
404
-
405
-
406
- def hexdec4(s)
407
- if s.length != 4
408
- raise Error, 'short'
409
- end
410
- (nibble(s[0])<<12) | (nibble(s[1])<<8) | (nibble(s[2])<<4) | nibble(s[3])
411
- end
412
-
413
-
414
- def subst(u1, u2)
415
- if Usurr1 <= u1 && u1 < Usurr2 && Usurr2 <= u2 && u2 < Usurr3
416
- return ((u1-Usurr1)<<10) | (u2-Usurr2) + Usurrself
417
- end
418
- return Ucharerr
419
- end
420
-
421
-
422
- def surrogate?(u)
423
- Usurr1 <= u && u < Usurr3
424
- end
425
-
426
-
427
- def nibble(c)
428
- if ?0 <= c && c <= ?9 then c.ord - ?0.ord
429
- elsif ?a <= c && c <= ?z then c.ord - ?a.ord + 10
430
- elsif ?A <= c && c <= ?Z then c.ord - ?A.ord + 10
431
- else
432
- raise Error, "invalid hex code #{c}"
433
- end
434
- end
435
-
436
-
437
- def objenc(x)
438
- '{' + x.map{|k,v| keyenc(k) + ':' + valenc(v)}.join(',') + '}'
439
- end
440
-
441
-
442
- def arrenc(a)
443
- '[' + a.map{|x| valenc(x)}.join(',') + ']'
444
- end
445
-
446
-
447
- def keyenc(k)
448
- case k
449
- when String then strenc(k)
450
- when Symbol then strenc(k.to_s)
451
- when Fixnum then strenc(k.to_s)
452
- else
453
- raise Error, "Hash key is not a string: #{k.inspect}"
454
- end
455
- end
456
-
457
-
458
- def strenc(s)
459
- t = StringIO.new
460
- t.putc(?")
461
- r = 0
462
-
463
- while r < s.length
464
- case s[r]
465
- when ?" then t.print('\\"')
466
- when ?\\ then t.print('\\\\')
467
- when ?\b then t.print('\\b')
468
- when ?\f then t.print('\\f')
469
- when ?\n then t.print('\\n')
470
- when ?\r then t.print('\\r')
471
- when ?\t then t.print('\\t')
472
- else
473
- c = s[r]
474
- # In ruby >= 1.9, s[r] is a codepoint, not a byte.
475
- if rubydoesenc?
476
- begin
477
- # c.ord will raise an error if c is invalid UTF-8
478
- if c.ord < Spc.ord
479
- c = "\\u%04x" % [c.ord]
480
- end
481
- t.write(c)
482
- rescue
483
- t.write(Ustrerr)
484
- end
485
- elsif c < Spc
486
- t.write("\\u%04x" % c)
487
- elsif Spc <= c && c <= ?~
488
- t.putc(c)
489
- else
490
- n = ucharcopy(t, s, r) # ensure valid UTF-8 output
491
- r += n - 1 # r is incremented below
492
- end
493
- end
494
- r += 1
495
- end
496
- t.putc(?")
497
- t.string
498
- end
499
-
500
-
501
- def numenc(x)
502
- if ((x.nan? || x.infinite?) rescue false)
503
- return strenc(x.to_s)
504
- end
505
- "#{x}"
506
- end
507
-
508
-
509
- # Copies the valid UTF-8 bytes of a single character
510
- # from string s at position i to I/O object t, and
511
- # returns the number of bytes copied.
512
- # If no valid UTF-8 char exists at position i,
513
- # ucharcopy writes Ustrerr and returns 1.
514
- def ucharcopy(t, s, i)
515
- n = s.length - i
516
- raise Utf8Error if n < 1
517
-
518
- c0 = s[i].ord
519
-
520
- # 1-byte, 7-bit sequence?
521
- if c0 < Utagx
522
- t.putc(c0)
523
- return 1
524
- end
525
-
526
- raise Utf8Error if c0 < Utag2 # unexpected continuation byte?
527
-
528
- raise Utf8Error if n < 2 # need continuation byte
529
- c1 = s[i+1].ord
530
- raise Utf8Error if c1 < Utagx || Utag2 <= c1
531
-
532
- # 2-byte, 11-bit sequence?
533
- if c0 < Utag3
534
- raise Utf8Error if ((c0&Umask2)<<6 | (c1&Umaskx)) <= Uchar1max
535
- t.putc(c0)
536
- t.putc(c1)
537
- return 2
538
- end
539
-
540
- # need second continuation byte
541
- raise Utf8Error if n < 3
542
-
543
- c2 = s[i+2].ord
544
- raise Utf8Error if c2 < Utagx || Utag2 <= c2
545
-
546
- # 3-byte, 16-bit sequence?
547
- if c0 < Utag4
548
- u = (c0&Umask3)<<12 | (c1&Umaskx)<<6 | (c2&Umaskx)
549
- raise Utf8Error if u <= Uchar2max
550
- t.putc(c0)
551
- t.putc(c1)
552
- t.putc(c2)
553
- return 3
554
- end
555
-
556
- # need third continuation byte
557
- raise Utf8Error if n < 4
558
- c3 = s[i+3].ord
559
- raise Utf8Error if c3 < Utagx || Utag2 <= c3
560
-
561
- # 4-byte, 21-bit sequence?
562
- if c0 < Utag5
563
- u = (c0&Umask4)<<18 | (c1&Umaskx)<<12 | (c2&Umaskx)<<6 | (c3&Umaskx)
564
- raise Utf8Error if u <= Uchar3max
565
- t.putc(c0)
566
- t.putc(c1)
567
- t.putc(c2)
568
- t.putc(c3)
569
- return 4
570
- end
571
-
572
- raise Utf8Error
573
- rescue Utf8Error
574
- t.write(Ustrerr)
575
- return 1
576
- end
577
-
578
-
579
- def rubydoesenc?
580
- ::String.method_defined?(:force_encoding)
581
- end
582
-
583
-
584
- class Utf8Error < ::StandardError
585
- end
586
-
587
-
588
- class Error < ::StandardError
589
- end
590
-
591
-
592
- Utagx = 0b1000_0000
593
- Utag2 = 0b1100_0000
594
- Utag3 = 0b1110_0000
595
- Utag4 = 0b1111_0000
596
- Utag5 = 0b1111_1000
597
- Umaskx = 0b0011_1111
598
- Umask2 = 0b0001_1111
599
- Umask3 = 0b0000_1111
600
- Umask4 = 0b0000_0111
601
- Uchar1max = (1<<7) - 1
602
- Uchar2max = (1<<11) - 1
603
- Uchar3max = (1<<16) - 1
604
- Ucharerr = 0xFFFD # unicode "replacement char"
605
- Ustrerr = "\xef\xbf\xbd" # unicode "replacement char"
606
- Usurrself = 0x10000
607
- Usurr1 = 0xd800
608
- Usurr2 = 0xdc00
609
- Usurr3 = 0xe000
610
-
611
- Spc = ' '[0]
612
- Unesc = {?b=>?\b, ?f=>?\f, ?n=>?\n, ?r=>?\r, ?t=>?\t}
613
- end
614
- end