upfluence-thrift 1.0.1

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