thrift 0.8.0 → 0.13.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.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/{README → README.md} +0 -0
  3. data/ext/binary_protocol_accelerated.c +33 -14
  4. data/ext/bytes.c +36 -0
  5. data/ext/bytes.h +31 -0
  6. data/ext/compact_protocol.c +27 -8
  7. data/ext/constants.h +8 -5
  8. data/ext/extconf.rb +5 -1
  9. data/ext/memory_buffer.c +12 -9
  10. data/ext/protocol.c +0 -185
  11. data/ext/protocol.h +0 -20
  12. data/ext/strlcpy.h +7 -3
  13. data/ext/struct.c +27 -7
  14. data/ext/thrift_native.c +16 -11
  15. data/lib/thrift.rb +10 -4
  16. data/lib/thrift/bytes.rb +131 -0
  17. data/lib/thrift/client.rb +13 -4
  18. data/lib/thrift/exceptions.rb +3 -0
  19. data/lib/thrift/multiplexed_processor.rb +76 -0
  20. data/lib/thrift/processor.rb +24 -6
  21. data/lib/thrift/protocol/base_protocol.rb +109 -12
  22. data/lib/thrift/protocol/binary_protocol.rb +22 -7
  23. data/lib/thrift/protocol/binary_protocol_accelerated.rb +8 -0
  24. data/lib/thrift/protocol/compact_protocol.rb +23 -6
  25. data/lib/thrift/protocol/json_protocol.rb +786 -0
  26. data/lib/thrift/protocol/multiplexed_protocol.rb +44 -0
  27. data/lib/thrift/protocol/protocol_decorator.rb +194 -0
  28. data/lib/thrift/server/base_server.rb +8 -2
  29. data/lib/thrift/server/mongrel_http_server.rb +2 -0
  30. data/lib/thrift/server/simple_server.rb +5 -1
  31. data/lib/thrift/server/thin_http_server.rb +91 -0
  32. data/lib/thrift/server/thread_pool_server.rb +5 -1
  33. data/lib/thrift/server/threaded_server.rb +5 -1
  34. data/lib/thrift/struct.rb +1 -1
  35. data/lib/thrift/struct_union.rb +2 -2
  36. data/lib/thrift/transport/base_server_transport.rb +1 -1
  37. data/lib/thrift/transport/base_transport.rb +30 -20
  38. data/lib/thrift/transport/buffered_transport.rb +25 -11
  39. data/lib/thrift/transport/framed_transport.rb +20 -11
  40. data/lib/thrift/transport/http_client_transport.rb +16 -6
  41. data/lib/thrift/transport/io_stream_transport.rb +5 -2
  42. data/lib/thrift/transport/memory_buffer_transport.rb +10 -6
  43. data/lib/thrift/transport/server_socket.rb +6 -1
  44. data/lib/thrift/transport/socket.rb +23 -17
  45. data/lib/thrift/transport/ssl_server_socket.rb +41 -0
  46. data/lib/thrift/transport/ssl_socket.rb +51 -0
  47. data/lib/thrift/transport/unix_server_socket.rb +5 -1
  48. data/lib/thrift/transport/unix_socket.rb +5 -1
  49. data/lib/thrift/union.rb +3 -6
  50. data/spec/BaseService.thrift +27 -0
  51. data/spec/ExtendedService.thrift +25 -0
  52. data/spec/Referenced.thrift +44 -0
  53. data/spec/ThriftNamespacedSpec.thrift +53 -0
  54. data/spec/ThriftSpec.thrift +52 -1
  55. data/spec/base_protocol_spec.rb +158 -93
  56. data/spec/base_transport_spec.rb +194 -157
  57. data/spec/binary_protocol_accelerated_spec.rb +14 -14
  58. data/spec/binary_protocol_spec.rb +29 -16
  59. data/spec/binary_protocol_spec_shared.rb +148 -65
  60. data/spec/bytes_spec.rb +160 -0
  61. data/spec/client_spec.rb +45 -47
  62. data/spec/compact_protocol_spec.rb +36 -22
  63. data/spec/exception_spec.rb +79 -80
  64. data/spec/flat_spec.rb +62 -0
  65. data/spec/http_client_spec.rb +91 -16
  66. data/spec/json_protocol_spec.rb +552 -0
  67. data/spec/namespaced_spec.rb +67 -0
  68. data/spec/nonblocking_server_spec.rb +26 -28
  69. data/spec/processor_spec.rb +29 -32
  70. data/spec/serializer_spec.rb +31 -33
  71. data/spec/server_socket_spec.rb +32 -28
  72. data/spec/server_spec.rb +112 -84
  73. data/spec/socket_spec.rb +27 -20
  74. data/spec/socket_spec_shared.rb +32 -32
  75. data/spec/spec_helper.rb +17 -11
  76. data/spec/ssl_server_socket_spec.rb +34 -0
  77. data/spec/ssl_socket_spec.rb +78 -0
  78. data/spec/struct_nested_containers_spec.rb +191 -0
  79. data/spec/struct_spec.rb +159 -161
  80. data/spec/thin_http_server_spec.rb +141 -0
  81. data/spec/types_spec.rb +71 -69
  82. data/spec/union_spec.rb +97 -76
  83. data/spec/unix_socket_spec.rb +49 -41
  84. metadata +268 -188
  85. data/CHANGELOG +0 -1
  86. data/benchmark/gen-rb/benchmark_constants.rb +0 -10
  87. data/benchmark/gen-rb/benchmark_service.rb +0 -80
  88. data/benchmark/gen-rb/benchmark_types.rb +0 -9
  89. data/spec/gen-rb/nonblocking_service.rb +0 -272
  90. data/spec/gen-rb/thrift_spec_constants.rb +0 -10
  91. data/spec/gen-rb/thrift_spec_types.rb +0 -345
  92. data/spec/mongrel_http_server_spec.rb +0 -117
  93. data/test/debug_proto/gen-rb/debug_proto_test_constants.rb +0 -273
  94. data/test/debug_proto/gen-rb/debug_proto_test_types.rb +0 -760
  95. data/test/debug_proto/gen-rb/empty_service.rb +0 -24
  96. data/test/debug_proto/gen-rb/inherited.rb +0 -79
  97. data/test/debug_proto/gen-rb/reverse_order_service.rb +0 -82
  98. data/test/debug_proto/gen-rb/service_for_exception_with_a_map.rb +0 -81
  99. data/test/debug_proto/gen-rb/srv.rb +0 -330
@@ -0,0 +1,786 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ #
20
+
21
+ require 'base64'
22
+
23
+ module Thrift
24
+ class LookaheadReader
25
+ def initialize(trans)
26
+ @trans = trans
27
+ @hasData = false
28
+ @data = nil
29
+ end
30
+
31
+ def read
32
+ if @hasData
33
+ @hasData = false
34
+ else
35
+ @data = @trans.read(1)
36
+ end
37
+
38
+ return @data
39
+ end
40
+
41
+ def peek
42
+ if !@hasData
43
+ @data = @trans.read(1)
44
+ end
45
+ @hasData = true
46
+ return @data
47
+ end
48
+ end
49
+
50
+ #
51
+ # Class to serve as base JSON context and as base class for other context
52
+ # implementations
53
+ #
54
+ class JSONContext
55
+ @@kJSONElemSeparator = ','
56
+ #
57
+ # Write context data to the trans. Default is to do nothing.
58
+ #
59
+ def write(trans)
60
+ end
61
+
62
+ #
63
+ # Read context data from the trans. Default is to do nothing.
64
+ #
65
+ def read(reader)
66
+ end
67
+
68
+ #
69
+ # Return true if numbers need to be escaped as strings in this context.
70
+ # Default behavior is to return false.
71
+ #
72
+ def escapeNum
73
+ return false
74
+ end
75
+ end
76
+
77
+ # Context class for object member key-value pairs
78
+ class JSONPairContext < JSONContext
79
+ @@kJSONPairSeparator = ':'
80
+
81
+ def initialize
82
+ @first = true
83
+ @colon = true
84
+ end
85
+
86
+ def write(trans)
87
+ if (@first)
88
+ @first = false
89
+ @colon = true
90
+ else
91
+ trans.write(@colon ? @@kJSONPairSeparator : @@kJSONElemSeparator)
92
+ @colon = !@colon
93
+ end
94
+ end
95
+
96
+ def read(reader)
97
+ if (@first)
98
+ @first = false
99
+ @colon = true
100
+ else
101
+ ch = (@colon ? @@kJSONPairSeparator : @@kJSONElemSeparator)
102
+ @colon = !@colon
103
+ JsonProtocol::read_syntax_char(reader, ch)
104
+ end
105
+ end
106
+
107
+ # Numbers must be turned into strings if they are the key part of a pair
108
+ def escapeNum
109
+ return @colon
110
+ end
111
+ end
112
+
113
+ # Context class for lists
114
+ class JSONListContext < JSONContext
115
+
116
+ def initialize
117
+ @first = true
118
+ end
119
+
120
+ def write(trans)
121
+ if (@first)
122
+ @first = false
123
+ else
124
+ trans.write(@@kJSONElemSeparator)
125
+ end
126
+ end
127
+
128
+ def read(reader)
129
+ if (@first)
130
+ @first = false
131
+ else
132
+ JsonProtocol::read_syntax_char(reader, @@kJSONElemSeparator)
133
+ end
134
+ end
135
+ end
136
+
137
+ class JsonProtocol < BaseProtocol
138
+
139
+ @@kJSONObjectStart = '{'
140
+ @@kJSONObjectEnd = '}'
141
+ @@kJSONArrayStart = '['
142
+ @@kJSONArrayEnd = ']'
143
+ @@kJSONNewline = '\n'
144
+ @@kJSONBackslash = '\\'
145
+ @@kJSONStringDelimiter = '"'
146
+
147
+ @@kThriftVersion1 = 1
148
+
149
+ @@kThriftNan = "NaN"
150
+ @@kThriftInfinity = "Infinity"
151
+ @@kThriftNegativeInfinity = "-Infinity"
152
+
153
+ def initialize(trans)
154
+ super(trans)
155
+ @context = JSONContext.new
156
+ @contexts = Array.new
157
+ @reader = LookaheadReader.new(trans)
158
+ end
159
+
160
+ def get_type_name_for_type_id(id)
161
+ case id
162
+ when Types::BOOL
163
+ "tf"
164
+ when Types::BYTE
165
+ "i8"
166
+ when Types::I16
167
+ "i16"
168
+ when Types::I32
169
+ "i32"
170
+ when Types::I64
171
+ "i64"
172
+ when Types::DOUBLE
173
+ "dbl"
174
+ when Types::STRING
175
+ "str"
176
+ when Types::STRUCT
177
+ "rec"
178
+ when Types::MAP
179
+ "map"
180
+ when Types::SET
181
+ "set"
182
+ when Types::LIST
183
+ "lst"
184
+ else
185
+ raise NotImplementedError
186
+ end
187
+ end
188
+
189
+ def get_type_id_for_type_name(name)
190
+ if (name == "tf")
191
+ result = Types::BOOL
192
+ elsif (name == "i8")
193
+ result = Types::BYTE
194
+ elsif (name == "i16")
195
+ result = Types::I16
196
+ elsif (name == "i32")
197
+ result = Types::I32
198
+ elsif (name == "i64")
199
+ result = Types::I64
200
+ elsif (name == "dbl")
201
+ result = Types::DOUBLE
202
+ elsif (name == "str")
203
+ result = Types::STRING
204
+ elsif (name == "rec")
205
+ result = Types::STRUCT
206
+ elsif (name == "map")
207
+ result = Types::MAP
208
+ elsif (name == "set")
209
+ result = Types::SET
210
+ elsif (name == "lst")
211
+ result = Types::LIST
212
+ else
213
+ result = Types::STOP
214
+ end
215
+ if (result == Types::STOP)
216
+ raise NotImplementedError
217
+ end
218
+ return result
219
+ end
220
+
221
+ # Static helper functions
222
+
223
+ # Read 1 character from the trans and verify that it is the expected character ch.
224
+ # Throw a protocol exception if it is not.
225
+ def self.read_syntax_char(reader, ch)
226
+ ch2 = reader.read
227
+ if (ch2 != ch)
228
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected \'#{ch}\' got \'#{ch2}\'.")
229
+ end
230
+ end
231
+
232
+ # Return true if the character ch is in [-+0-9.Ee]; false otherwise
233
+ def is_json_numeric(ch)
234
+ case ch
235
+ when '+', '-', '.', '0' .. '9', 'E', "e"
236
+ return true
237
+ else
238
+ return false
239
+ end
240
+ end
241
+
242
+ def push_context(context)
243
+ @contexts.push(@context)
244
+ @context = context
245
+ end
246
+
247
+ def pop_context
248
+ @context = @contexts.pop
249
+ end
250
+
251
+ # Write the character ch as a JSON escape sequence ("\u00xx")
252
+ def write_json_escape_char(ch)
253
+ trans.write('\\u')
254
+ ch_value = ch[0]
255
+ if (ch_value.kind_of? String)
256
+ ch_value = ch.bytes.first
257
+ end
258
+ trans.write(ch_value.to_s(16).rjust(4,'0'))
259
+ end
260
+
261
+ # Write the character ch as part of a JSON string, escaping as appropriate.
262
+ def write_json_char(ch)
263
+ # This table describes the handling for the first 0x30 characters
264
+ # 0 : escape using "\u00xx" notation
265
+ # 1 : just output index
266
+ # <other> : escape using "\<other>" notation
267
+ kJSONCharTable = [
268
+ # 0 1 2 3 4 5 6 7 8 9 A B C D E F
269
+ 0, 0, 0, 0, 0, 0, 0, 0,'b','t','n', 0,'f','r', 0, 0, # 0
270
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 1
271
+ 1, 1,'"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 2
272
+ ]
273
+
274
+ ch_value = ch[0]
275
+ if (ch_value.kind_of? String)
276
+ ch_value = ch.bytes.first
277
+ end
278
+ if (ch_value >= 0x30)
279
+ if (ch == @@kJSONBackslash) # Only special character >= 0x30 is '\'
280
+ trans.write(@@kJSONBackslash)
281
+ trans.write(@@kJSONBackslash)
282
+ else
283
+ trans.write(ch)
284
+ end
285
+ else
286
+ outCh = kJSONCharTable[ch_value];
287
+ # Check if regular character, backslash escaped, or JSON escaped
288
+ if outCh.kind_of? String
289
+ trans.write(@@kJSONBackslash)
290
+ trans.write(outCh)
291
+ elsif outCh == 1
292
+ trans.write(ch)
293
+ else
294
+ write_json_escape_char(ch)
295
+ end
296
+ end
297
+ end
298
+
299
+ # Write out the contents of the string str as a JSON string, escaping characters as appropriate.
300
+ def write_json_string(str)
301
+ @context.write(trans)
302
+ trans.write(@@kJSONStringDelimiter)
303
+ str.split('').each do |ch|
304
+ write_json_char(ch)
305
+ end
306
+ trans.write(@@kJSONStringDelimiter)
307
+ end
308
+
309
+ # Write out the contents of the string as JSON string, base64-encoding
310
+ # the string's contents, and escaping as appropriate
311
+ def write_json_base64(str)
312
+ @context.write(trans)
313
+ trans.write(@@kJSONStringDelimiter)
314
+ trans.write(Base64.strict_encode64(str))
315
+ trans.write(@@kJSONStringDelimiter)
316
+ end
317
+
318
+ # Convert the given integer type to a JSON number, or a string
319
+ # if the context requires it (eg: key in a map pair).
320
+ def write_json_integer(num)
321
+ @context.write(trans)
322
+ escapeNum = @context.escapeNum
323
+ if (escapeNum)
324
+ trans.write(@@kJSONStringDelimiter)
325
+ end
326
+ trans.write(num.to_s);
327
+ if (escapeNum)
328
+ trans.write(@@kJSONStringDelimiter)
329
+ end
330
+ end
331
+
332
+ # Convert the given double to a JSON string, which is either the number,
333
+ # "NaN" or "Infinity" or "-Infinity".
334
+ def write_json_double(num)
335
+ @context.write(trans)
336
+ # Normalize output of thrift::to_string for NaNs and Infinities
337
+ special = false;
338
+ if (num.nan?)
339
+ special = true;
340
+ val = @@kThriftNan;
341
+ elsif (num.infinite?)
342
+ special = true;
343
+ val = @@kThriftInfinity;
344
+ if (num < 0.0)
345
+ val = @@kThriftNegativeInfinity;
346
+ end
347
+ else
348
+ val = num.to_s
349
+ end
350
+
351
+ escapeNum = special || @context.escapeNum
352
+ if (escapeNum)
353
+ trans.write(@@kJSONStringDelimiter)
354
+ end
355
+ trans.write(val)
356
+ if (escapeNum)
357
+ trans.write(@@kJSONStringDelimiter)
358
+ end
359
+ end
360
+
361
+ def write_json_object_start
362
+ @context.write(trans)
363
+ trans.write(@@kJSONObjectStart)
364
+ push_context(JSONPairContext.new);
365
+ end
366
+
367
+ def write_json_object_end
368
+ pop_context
369
+ trans.write(@@kJSONObjectEnd)
370
+ end
371
+
372
+ def write_json_array_start
373
+ @context.write(trans)
374
+ trans.write(@@kJSONArrayStart)
375
+ push_context(JSONListContext.new);
376
+ end
377
+
378
+ def write_json_array_end
379
+ pop_context
380
+ trans.write(@@kJSONArrayEnd)
381
+ end
382
+
383
+ def write_message_begin(name, type, seqid)
384
+ write_json_array_start
385
+ write_json_integer(@@kThriftVersion1)
386
+ write_json_string(name)
387
+ write_json_integer(type)
388
+ write_json_integer(seqid)
389
+ end
390
+
391
+ def write_message_end
392
+ write_json_array_end
393
+ end
394
+
395
+ def write_struct_begin(name)
396
+ write_json_object_start
397
+ end
398
+
399
+ def write_struct_end
400
+ write_json_object_end
401
+ end
402
+
403
+ def write_field_begin(name, type, id)
404
+ write_json_integer(id)
405
+ write_json_object_start
406
+ write_json_string(get_type_name_for_type_id(type))
407
+ end
408
+
409
+ def write_field_end
410
+ write_json_object_end
411
+ end
412
+
413
+ def write_field_stop; nil; end
414
+
415
+ def write_map_begin(ktype, vtype, size)
416
+ write_json_array_start
417
+ write_json_string(get_type_name_for_type_id(ktype))
418
+ write_json_string(get_type_name_for_type_id(vtype))
419
+ write_json_integer(size)
420
+ write_json_object_start
421
+ end
422
+
423
+ def write_map_end
424
+ write_json_object_end
425
+ write_json_array_end
426
+ end
427
+
428
+ def write_list_begin(etype, size)
429
+ write_json_array_start
430
+ write_json_string(get_type_name_for_type_id(etype))
431
+ write_json_integer(size)
432
+ end
433
+
434
+ def write_list_end
435
+ write_json_array_end
436
+ end
437
+
438
+ def write_set_begin(etype, size)
439
+ write_json_array_start
440
+ write_json_string(get_type_name_for_type_id(etype))
441
+ write_json_integer(size)
442
+ end
443
+
444
+ def write_set_end
445
+ write_json_array_end
446
+ end
447
+
448
+ def write_bool(bool)
449
+ write_json_integer(bool ? 1 : 0)
450
+ end
451
+
452
+ def write_byte(byte)
453
+ write_json_integer(byte)
454
+ end
455
+
456
+ def write_i16(i16)
457
+ write_json_integer(i16)
458
+ end
459
+
460
+ def write_i32(i32)
461
+ write_json_integer(i32)
462
+ end
463
+
464
+ def write_i64(i64)
465
+ write_json_integer(i64)
466
+ end
467
+
468
+ def write_double(dub)
469
+ write_json_double(dub)
470
+ end
471
+
472
+ def write_string(str)
473
+ write_json_string(str)
474
+ end
475
+
476
+ def write_binary(str)
477
+ write_json_base64(str)
478
+ end
479
+
480
+ ##
481
+ # Reading functions
482
+ ##
483
+
484
+ # Reads 1 byte and verifies that it matches ch.
485
+ def read_json_syntax_char(ch)
486
+ JsonProtocol::read_syntax_char(@reader, ch)
487
+ end
488
+
489
+ # Decodes the four hex parts of a JSON escaped string character and returns
490
+ # the character via out.
491
+ #
492
+ # Note - this only supports Unicode characters in the BMP (U+0000 to U+FFFF);
493
+ # characters above the BMP are encoded as two escape sequences (surrogate pairs),
494
+ # which is not yet implemented
495
+ def read_json_escape_char
496
+ str = @reader.read
497
+ str += @reader.read
498
+ str += @reader.read
499
+ str += @reader.read
500
+ if RUBY_VERSION >= '1.9'
501
+ str.hex.chr(Encoding::UTF_8)
502
+ else
503
+ str.hex.chr
504
+ end
505
+ end
506
+
507
+ # Decodes a JSON string, including unescaping, and returns the string via str
508
+ def read_json_string(skipContext = false)
509
+ # This string's characters must match up with the elements in escape_char_vals.
510
+ # I don't have '/' on this list even though it appears on www.json.org --
511
+ # it is not in the RFC -> it is. See RFC 4627
512
+ escape_chars = "\"\\/bfnrt"
513
+
514
+ # The elements of this array must match up with the sequence of characters in
515
+ # escape_chars
516
+ escape_char_vals = [
517
+ "\"", "\\", "\/", "\b", "\f", "\n", "\r", "\t",
518
+ ]
519
+
520
+ if !skipContext
521
+ @context.read(@reader)
522
+ end
523
+ read_json_syntax_char(@@kJSONStringDelimiter)
524
+ ch = ""
525
+ str = ""
526
+ while (true)
527
+ ch = @reader.read
528
+ if (ch == @@kJSONStringDelimiter)
529
+ break
530
+ end
531
+ if (ch == @@kJSONBackslash)
532
+ ch = @reader.read
533
+ if (ch == 'u')
534
+ ch = read_json_escape_char
535
+ else
536
+ pos = escape_chars.index(ch);
537
+ if (pos.nil?) # not found
538
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected control char, got \'#{ch}\'.")
539
+ end
540
+ ch = escape_char_vals[pos]
541
+ end
542
+ end
543
+ str += ch
544
+ end
545
+ return str
546
+ end
547
+
548
+ # Reads a block of base64 characters, decoding it, and returns via str
549
+ def read_json_base64
550
+ str = read_json_string
551
+ m = str.length % 4
552
+ if m != 0
553
+ # Add missing padding
554
+ (4 - m).times do
555
+ str += '='
556
+ end
557
+ end
558
+ Base64.strict_decode64(str)
559
+ end
560
+
561
+ # Reads a sequence of characters, stopping at the first one that is not
562
+ # a valid JSON numeric character.
563
+ def read_json_numeric_chars
564
+ str = ""
565
+ while (true)
566
+ ch = @reader.peek
567
+ if (!is_json_numeric(ch))
568
+ break;
569
+ end
570
+ ch = @reader.read
571
+ str += ch
572
+ end
573
+ return str
574
+ end
575
+
576
+ # Reads a sequence of characters and assembles them into a number,
577
+ # returning them via num
578
+ def read_json_integer
579
+ @context.read(@reader)
580
+ if (@context.escapeNum)
581
+ read_json_syntax_char(@@kJSONStringDelimiter)
582
+ end
583
+ str = read_json_numeric_chars
584
+
585
+ begin
586
+ num = Integer(str);
587
+ rescue
588
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected numeric value; got \"#{str}\"")
589
+ end
590
+
591
+ if (@context.escapeNum)
592
+ read_json_syntax_char(@@kJSONStringDelimiter)
593
+ end
594
+
595
+ return num
596
+ end
597
+
598
+ # Reads a JSON number or string and interprets it as a double.
599
+ def read_json_double
600
+ @context.read(@reader)
601
+ num = 0
602
+ if (@reader.peek == @@kJSONStringDelimiter)
603
+ str = read_json_string(true)
604
+ # Check for NaN, Infinity and -Infinity
605
+ if (str == @@kThriftNan)
606
+ num = (+1.0/0.0)/(+1.0/0.0)
607
+ elsif (str == @@kThriftInfinity)
608
+ num = +1.0/0.0
609
+ elsif (str == @@kThriftNegativeInfinity)
610
+ num = -1.0/0.0
611
+ else
612
+ if (!@context.escapeNum)
613
+ # Raise exception -- we should not be in a string in this case
614
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Numeric data unexpectedly quoted")
615
+ end
616
+ begin
617
+ num = Float(str)
618
+ rescue
619
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected numeric value; got \"#{str}\"")
620
+ end
621
+ end
622
+ else
623
+ if (@context.escapeNum)
624
+ # This will throw - we should have had a quote if escapeNum == true
625
+ read_json_syntax_char(@@kJSONStringDelimiter)
626
+ end
627
+ str = read_json_numeric_chars
628
+ begin
629
+ num = Float(str)
630
+ rescue
631
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected numeric value; got \"#{str}\"")
632
+ end
633
+ end
634
+ return num
635
+ end
636
+
637
+ def read_json_object_start
638
+ @context.read(@reader)
639
+ read_json_syntax_char(@@kJSONObjectStart)
640
+ push_context(JSONPairContext.new)
641
+ nil
642
+ end
643
+
644
+ def read_json_object_end
645
+ read_json_syntax_char(@@kJSONObjectEnd)
646
+ pop_context
647
+ nil
648
+ end
649
+
650
+ def read_json_array_start
651
+ @context.read(@reader)
652
+ read_json_syntax_char(@@kJSONArrayStart)
653
+ push_context(JSONListContext.new)
654
+ nil
655
+ end
656
+
657
+ def read_json_array_end
658
+ read_json_syntax_char(@@kJSONArrayEnd)
659
+ pop_context
660
+ nil
661
+ end
662
+
663
+ def read_message_begin
664
+ read_json_array_start
665
+ version = read_json_integer
666
+ if (version != @@kThriftVersion1)
667
+ raise ProtocolException.new(ProtocolException::BAD_VERSION, 'Message contained bad version.')
668
+ end
669
+ name = read_json_string
670
+ message_type = read_json_integer
671
+ seqid = read_json_integer
672
+ [name, message_type, seqid]
673
+ end
674
+
675
+ def read_message_end
676
+ read_json_array_end
677
+ nil
678
+ end
679
+
680
+ def read_struct_begin
681
+ read_json_object_start
682
+ nil
683
+ end
684
+
685
+ def read_struct_end
686
+ read_json_object_end
687
+ nil
688
+ end
689
+
690
+ def read_field_begin
691
+ # Check if we hit the end of the list
692
+ ch = @reader.peek
693
+ if (ch == @@kJSONObjectEnd)
694
+ field_type = Types::STOP
695
+ else
696
+ field_id = read_json_integer
697
+ read_json_object_start
698
+ field_type = get_type_id_for_type_name(read_json_string)
699
+ end
700
+ [nil, field_type, field_id]
701
+ end
702
+
703
+ def read_field_end
704
+ read_json_object_end
705
+ end
706
+
707
+ def read_map_begin
708
+ read_json_array_start
709
+ key_type = get_type_id_for_type_name(read_json_string)
710
+ val_type = get_type_id_for_type_name(read_json_string)
711
+ size = read_json_integer
712
+ read_json_object_start
713
+ [key_type, val_type, size]
714
+ end
715
+
716
+ def read_map_end
717
+ read_json_object_end
718
+ read_json_array_end
719
+ end
720
+
721
+ def read_list_begin
722
+ read_json_array_start
723
+ [get_type_id_for_type_name(read_json_string), read_json_integer]
724
+ end
725
+
726
+ def read_list_end
727
+ read_json_array_end
728
+ end
729
+
730
+ def read_set_begin
731
+ read_json_array_start
732
+ [get_type_id_for_type_name(read_json_string), read_json_integer]
733
+ end
734
+
735
+ def read_set_end
736
+ read_json_array_end
737
+ end
738
+
739
+ def read_bool
740
+ byte = read_byte
741
+ byte != 0
742
+ end
743
+
744
+ def read_byte
745
+ read_json_integer
746
+ end
747
+
748
+ def read_i16
749
+ read_json_integer
750
+ end
751
+
752
+ def read_i32
753
+ read_json_integer
754
+ end
755
+
756
+ def read_i64
757
+ read_json_integer
758
+ end
759
+
760
+ def read_double
761
+ read_json_double
762
+ end
763
+
764
+ def read_string
765
+ read_json_string
766
+ end
767
+
768
+ def read_binary
769
+ read_json_base64
770
+ end
771
+
772
+ def to_s
773
+ "json(#{super.to_s})"
774
+ end
775
+ end
776
+
777
+ class JsonProtocolFactory < BaseProtocolFactory
778
+ def get_protocol(trans)
779
+ return Thrift::JsonProtocol.new(trans)
780
+ end
781
+
782
+ def to_s
783
+ "json"
784
+ end
785
+ end
786
+ end