thrift 0.8.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
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