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.
- checksums.yaml +7 -0
- data/README.md +43 -0
- data/benchmark/Benchmark.thrift +24 -0
- data/benchmark/benchmark.rb +271 -0
- data/benchmark/client.rb +74 -0
- data/benchmark/gen-rb/benchmark_constants.rb +11 -0
- data/benchmark/gen-rb/benchmark_service.rb +80 -0
- data/benchmark/gen-rb/benchmark_types.rb +10 -0
- data/benchmark/server.rb +82 -0
- data/benchmark/thin_server.rb +44 -0
- data/ext/binary_protocol_accelerated.c +460 -0
- data/ext/binary_protocol_accelerated.h +20 -0
- data/ext/bytes.c +36 -0
- data/ext/bytes.h +31 -0
- data/ext/compact_protocol.c +637 -0
- data/ext/compact_protocol.h +20 -0
- data/ext/constants.h +99 -0
- data/ext/extconf.rb +34 -0
- data/ext/macros.h +41 -0
- data/ext/memory_buffer.c +134 -0
- data/ext/memory_buffer.h +20 -0
- data/ext/protocol.c +0 -0
- data/ext/protocol.h +0 -0
- data/ext/strlcpy.c +41 -0
- data/ext/strlcpy.h +34 -0
- data/ext/struct.c +707 -0
- data/ext/struct.h +25 -0
- data/ext/thrift_native.c +201 -0
- data/lib/thrift.rb +68 -0
- data/lib/thrift/bytes.rb +131 -0
- data/lib/thrift/client.rb +71 -0
- data/lib/thrift/core_ext.rb +23 -0
- data/lib/thrift/core_ext/fixnum.rb +29 -0
- data/lib/thrift/exceptions.rb +87 -0
- data/lib/thrift/multiplexed_processor.rb +76 -0
- data/lib/thrift/processor.rb +57 -0
- data/lib/thrift/protocol/base_protocol.rb +379 -0
- data/lib/thrift/protocol/binary_protocol.rb +237 -0
- data/lib/thrift/protocol/binary_protocol_accelerated.rb +39 -0
- data/lib/thrift/protocol/compact_protocol.rb +435 -0
- data/lib/thrift/protocol/json_protocol.rb +769 -0
- data/lib/thrift/protocol/multiplexed_protocol.rb +40 -0
- data/lib/thrift/protocol/protocol_decorator.rb +194 -0
- data/lib/thrift/serializer/deserializer.rb +33 -0
- data/lib/thrift/serializer/serializer.rb +34 -0
- data/lib/thrift/server/base_server.rb +31 -0
- data/lib/thrift/server/mongrel_http_server.rb +60 -0
- data/lib/thrift/server/nonblocking_server.rb +305 -0
- data/lib/thrift/server/rack_application.rb +61 -0
- data/lib/thrift/server/simple_server.rb +43 -0
- data/lib/thrift/server/thin_http_server.rb +51 -0
- data/lib/thrift/server/thread_pool_server.rb +75 -0
- data/lib/thrift/server/threaded_server.rb +47 -0
- data/lib/thrift/struct.rb +237 -0
- data/lib/thrift/struct_union.rb +192 -0
- data/lib/thrift/thrift_native.rb +24 -0
- data/lib/thrift/transport/base_server_transport.rb +37 -0
- data/lib/thrift/transport/base_transport.rb +109 -0
- data/lib/thrift/transport/buffered_transport.rb +114 -0
- data/lib/thrift/transport/framed_transport.rb +117 -0
- data/lib/thrift/transport/http_client_transport.rb +56 -0
- data/lib/thrift/transport/io_stream_transport.rb +39 -0
- data/lib/thrift/transport/memory_buffer_transport.rb +125 -0
- data/lib/thrift/transport/server_socket.rb +63 -0
- data/lib/thrift/transport/socket.rb +139 -0
- data/lib/thrift/transport/unix_server_socket.rb +60 -0
- data/lib/thrift/transport/unix_socket.rb +40 -0
- data/lib/thrift/types.rb +101 -0
- data/lib/thrift/union.rb +179 -0
- data/spec/BaseService.thrift +27 -0
- data/spec/ExtendedService.thrift +25 -0
- data/spec/Referenced.thrift +44 -0
- data/spec/ThriftNamespacedSpec.thrift +53 -0
- data/spec/ThriftSpec.thrift +183 -0
- data/spec/base_protocol_spec.rb +217 -0
- data/spec/base_transport_spec.rb +350 -0
- data/spec/binary_protocol_accelerated_spec.rb +42 -0
- data/spec/binary_protocol_spec.rb +66 -0
- data/spec/binary_protocol_spec_shared.rb +455 -0
- data/spec/bytes_spec.rb +160 -0
- data/spec/client_spec.rb +99 -0
- data/spec/compact_protocol_spec.rb +143 -0
- data/spec/exception_spec.rb +141 -0
- data/spec/flat_spec.rb +62 -0
- data/spec/gen-rb/base/base_service.rb +80 -0
- data/spec/gen-rb/base/base_service_constants.rb +11 -0
- data/spec/gen-rb/base/base_service_types.rb +26 -0
- data/spec/gen-rb/extended/extended_service.rb +78 -0
- data/spec/gen-rb/extended/extended_service_constants.rb +11 -0
- data/spec/gen-rb/extended/extended_service_types.rb +12 -0
- data/spec/gen-rb/flat/namespaced_nonblocking_service.rb +272 -0
- data/spec/gen-rb/flat/referenced_constants.rb +11 -0
- data/spec/gen-rb/flat/referenced_types.rb +17 -0
- data/spec/gen-rb/flat/thrift_namespaced_spec_constants.rb +11 -0
- data/spec/gen-rb/flat/thrift_namespaced_spec_types.rb +28 -0
- data/spec/gen-rb/namespaced_spec_namespace/namespaced_nonblocking_service.rb +272 -0
- data/spec/gen-rb/namespaced_spec_namespace/thrift_namespaced_spec_constants.rb +11 -0
- data/spec/gen-rb/namespaced_spec_namespace/thrift_namespaced_spec_types.rb +28 -0
- data/spec/gen-rb/nonblocking_service.rb +272 -0
- data/spec/gen-rb/other_namespace/referenced_constants.rb +11 -0
- data/spec/gen-rb/other_namespace/referenced_types.rb +17 -0
- data/spec/gen-rb/thrift_spec_constants.rb +11 -0
- data/spec/gen-rb/thrift_spec_types.rb +538 -0
- data/spec/http_client_spec.rb +120 -0
- data/spec/json_protocol_spec.rb +513 -0
- data/spec/namespaced_spec.rb +67 -0
- data/spec/nonblocking_server_spec.rb +263 -0
- data/spec/processor_spec.rb +80 -0
- data/spec/serializer_spec.rb +67 -0
- data/spec/server_socket_spec.rb +79 -0
- data/spec/server_spec.rb +147 -0
- data/spec/socket_spec.rb +61 -0
- data/spec/socket_spec_shared.rb +104 -0
- data/spec/spec_helper.rb +64 -0
- data/spec/struct_nested_containers_spec.rb +191 -0
- data/spec/struct_spec.rb +293 -0
- data/spec/thin_http_server_spec.rb +141 -0
- data/spec/types_spec.rb +115 -0
- data/spec/union_spec.rb +203 -0
- data/spec/unix_socket_spec.rb +107 -0
- data/test/debug_proto/gen-rb/debug_proto_test_constants.rb +274 -0
- data/test/debug_proto/gen-rb/debug_proto_test_types.rb +761 -0
- data/test/debug_proto/gen-rb/empty_service.rb +24 -0
- data/test/debug_proto/gen-rb/inherited.rb +79 -0
- data/test/debug_proto/gen-rb/reverse_order_service.rb +82 -0
- data/test/debug_proto/gen-rb/service_for_exception_with_a_map.rb +81 -0
- data/test/debug_proto/gen-rb/srv.rb +330 -0
- 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
|