sentry-raven 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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