thrift 0.24.0 → 0.25.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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +107 -4
  3. data/ext/binary_protocol_accelerated.c +52 -17
  4. data/ext/compact_protocol.c +135 -70
  5. data/ext/constants.h +3 -0
  6. data/ext/extconf.rb +4 -4
  7. data/ext/macros.h +11 -0
  8. data/ext/memory_buffer.c +35 -17
  9. data/ext/struct.c +185 -64
  10. data/ext/thrift_native.c +6 -0
  11. data/lib/thrift/bytes.rb +2 -2
  12. data/lib/thrift/client.rb +31 -22
  13. data/lib/thrift/exceptions.rb +10 -8
  14. data/lib/thrift/multiplexed_processor.rb +5 -6
  15. data/lib/thrift/processor.rb +24 -3
  16. data/lib/thrift/protocol/base_protocol.rb +53 -27
  17. data/lib/thrift/protocol/binary_protocol.rb +54 -40
  18. data/lib/thrift/protocol/binary_protocol_accelerated.rb +6 -2
  19. data/lib/thrift/protocol/compact_protocol.rb +193 -88
  20. data/lib/thrift/protocol/header_protocol.rb +14 -3
  21. data/lib/thrift/protocol/json_protocol.rb +146 -104
  22. data/lib/thrift/protocol/multiplexed_protocol.rb +2 -3
  23. data/lib/thrift/protocol/protocol_decorator.rb +5 -2
  24. data/lib/thrift/serializer/serializer.rb +6 -0
  25. data/lib/thrift/server/base_server.rb +10 -2
  26. data/lib/thrift/server/nonblocking_server.rb +49 -26
  27. data/lib/thrift/server/rack_application.rb +69 -0
  28. data/lib/thrift/server/simple_server.rb +27 -23
  29. data/lib/thrift/server/thin_http_server.rb +20 -44
  30. data/lib/thrift/server/thread_pool_server.rb +20 -17
  31. data/lib/thrift/server/threaded_server.rb +22 -26
  32. data/lib/thrift/struct.rb +33 -18
  33. data/lib/thrift/struct_union.rb +36 -30
  34. data/lib/thrift/transport/base_transport.rb +23 -5
  35. data/lib/thrift/transport/buffered_transport.rb +4 -4
  36. data/lib/thrift/transport/framed_transport.rb +32 -7
  37. data/lib/thrift/transport/header_transport.rb +130 -50
  38. data/lib/thrift/transport/http_client_transport.rb +27 -14
  39. data/lib/thrift/transport/io_stream_transport.rb +2 -1
  40. data/lib/thrift/transport/memory_buffer_transport.rb +8 -10
  41. data/lib/thrift/transport/server_socket.rb +4 -5
  42. data/lib/thrift/transport/socket.rb +20 -22
  43. data/lib/thrift/transport/ssl_server_socket.rb +64 -4
  44. data/lib/thrift/transport/ssl_socket.rb +32 -5
  45. data/lib/thrift/transport/unix_server_socket.rb +1 -1
  46. data/lib/thrift/transport/unix_socket.rb +4 -6
  47. data/lib/thrift/types.rb +22 -22
  48. data/lib/thrift/union.rb +20 -11
  49. data/lib/thrift/uuid.rb +8 -8
  50. data/lib/thrift.rb +39 -39
  51. metadata +5 -230
  52. data/benchmark/Benchmark.thrift +0 -24
  53. data/benchmark/benchmark.rb +0 -286
  54. data/benchmark/client.rb +0 -118
  55. data/benchmark/server.rb +0 -121
  56. data/benchmark/thin_server.rb +0 -46
  57. data/lib/thrift/server/mongrel_http_server.rb +0 -61
  58. data/spec/BaseService.thrift +0 -27
  59. data/spec/ExtendedService.thrift +0 -25
  60. data/spec/Referenced.thrift +0 -44
  61. data/spec/ThriftNamespacedSpec.thrift +0 -53
  62. data/spec/ThriftSpec.thrift +0 -203
  63. data/spec/base_protocol_spec.rb +0 -244
  64. data/spec/base_transport_spec.rb +0 -428
  65. data/spec/binary_protocol_accelerated_spec.rb +0 -47
  66. data/spec/binary_protocol_spec.rb +0 -73
  67. data/spec/binary_protocol_spec_shared.rb +0 -509
  68. data/spec/bytes_spec.rb +0 -117
  69. data/spec/client_spec.rb +0 -167
  70. data/spec/compact_protocol_spec.rb +0 -295
  71. data/spec/constants_demo_spec.rb +0 -102
  72. data/spec/exception_spec.rb +0 -141
  73. data/spec/flat_spec.rb +0 -63
  74. data/spec/header_protocol_spec.rb +0 -476
  75. data/spec/header_transport_spec.rb +0 -431
  76. data/spec/http_client_spec.rb +0 -160
  77. data/spec/json_protocol_spec.rb +0 -574
  78. data/spec/multiplexed_processor_spec.rb +0 -75
  79. data/spec/namespaced_spec.rb +0 -67
  80. data/spec/nonblocking_server_spec.rb +0 -429
  81. data/spec/processor_spec.rb +0 -80
  82. data/spec/recursion_depth_spec.rb +0 -223
  83. data/spec/serializer_spec.rb +0 -67
  84. data/spec/server_socket_spec.rb +0 -121
  85. data/spec/server_spec.rb +0 -238
  86. data/spec/socket_spec.rb +0 -174
  87. data/spec/socket_spec_shared.rb +0 -168
  88. data/spec/spec_helper.rb +0 -70
  89. data/spec/ssl_server_socket_spec.rb +0 -85
  90. data/spec/ssl_socket_spec.rb +0 -248
  91. data/spec/struct_nested_containers_spec.rb +0 -191
  92. data/spec/struct_spec.rb +0 -398
  93. data/spec/support/header_protocol_helper.rb +0 -55
  94. data/spec/thin_http_server_spec.rb +0 -127
  95. data/spec/types_spec.rb +0 -118
  96. data/spec/union_spec.rb +0 -273
  97. data/spec/unix_socket_spec.rb +0 -131
  98. data/spec/uuid_validation_spec.rb +0 -239
  99. data/test/fuzz/Makefile +0 -779
  100. data/test/fuzz/Makefile.am +0 -173
  101. data/test/fuzz/Makefile.in +0 -775
  102. data/test/fuzz/README.md +0 -149
  103. data/test/fuzz/fuzz_common.rb +0 -96
  104. data/test/fuzz/fuzz_parse_binary_protocol.rb +0 -23
  105. data/test/fuzz/fuzz_parse_binary_protocol_accelerated.rb +0 -23
  106. data/test/fuzz/fuzz_parse_binary_protocol_accelerated_harness.rb +0 -23
  107. data/test/fuzz/fuzz_parse_binary_protocol_harness.rb +0 -23
  108. data/test/fuzz/fuzz_parse_compact_protocol.rb +0 -23
  109. data/test/fuzz/fuzz_parse_compact_protocol_harness.rb +0 -23
  110. data/test/fuzz/fuzz_parse_json_protocol.rb +0 -23
  111. data/test/fuzz/fuzz_parse_json_protocol_harness.rb +0 -23
  112. data/test/fuzz/fuzz_roundtrip_binary_protocol.rb +0 -23
  113. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated.rb +0 -23
  114. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated_harness.rb +0 -23
  115. data/test/fuzz/fuzz_roundtrip_binary_protocol_harness.rb +0 -23
  116. data/test/fuzz/fuzz_roundtrip_compact_protocol.rb +0 -23
  117. data/test/fuzz/fuzz_roundtrip_compact_protocol_harness.rb +0 -23
  118. data/test/fuzz/fuzz_roundtrip_json_protocol.rb +0 -23
  119. data/test/fuzz/fuzz_roundtrip_json_protocol_harness.rb +0 -23
  120. data/test/fuzz/fuzz_tracer.rb +0 -29
@@ -34,7 +34,7 @@ module Thrift
34
34
  @data = @trans.read(1)
35
35
  end
36
36
 
37
- return @data
37
+ @data
38
38
  end
39
39
 
40
40
  def peek
@@ -42,7 +42,7 @@ module Thrift
42
42
  @data = @trans.read(1)
43
43
  end
44
44
  @hasData = true
45
- return @data
45
+ @data
46
46
  end
47
47
  end
48
48
 
@@ -51,7 +51,7 @@ module Thrift
51
51
  # implementations
52
52
  #
53
53
  class JSONContext
54
- @@kJSONElemSeparator = ','
54
+ @@kJSONElemSeparator = ","
55
55
  #
56
56
  # Write context data to the trans. Default is to do nothing.
57
57
  #
@@ -69,13 +69,13 @@ module Thrift
69
69
  # Default behavior is to return false.
70
70
  #
71
71
  def escapeNum
72
- return false
72
+ false
73
73
  end
74
74
  end
75
75
 
76
76
  # Context class for object member key-value pairs
77
77
  class JSONPairContext < JSONContext
78
- @@kJSONPairSeparator = ':'
78
+ @@kJSONPairSeparator = ":"
79
79
 
80
80
  def initialize
81
81
  @first = true
@@ -83,7 +83,7 @@ module Thrift
83
83
  end
84
84
 
85
85
  def write(trans)
86
- if (@first)
86
+ if @first
87
87
  @first = false
88
88
  @colon = true
89
89
  else
@@ -93,7 +93,7 @@ module Thrift
93
93
  end
94
94
 
95
95
  def read(reader)
96
- if (@first)
96
+ if @first
97
97
  @first = false
98
98
  @colon = true
99
99
  else
@@ -105,19 +105,18 @@ module Thrift
105
105
 
106
106
  # Numbers must be turned into strings if they are the key part of a pair
107
107
  def escapeNum
108
- return @colon
108
+ @colon
109
109
  end
110
110
  end
111
111
 
112
112
  # Context class for lists
113
113
  class JSONListContext < JSONContext
114
-
115
114
  def initialize
116
115
  @first = true
117
116
  end
118
117
 
119
118
  def write(trans)
120
- if (@first)
119
+ if @first
121
120
  @first = false
122
121
  else
123
122
  trans.write(@@kJSONElemSeparator)
@@ -125,7 +124,7 @@ module Thrift
125
124
  end
126
125
 
127
126
  def read(reader)
128
- if (@first)
127
+ if @first
129
128
  @first = false
130
129
  else
131
130
  JsonProtocol::read_syntax_char(reader, @@kJSONElemSeparator)
@@ -134,13 +133,14 @@ module Thrift
134
133
  end
135
134
 
136
135
  class JsonProtocol < BaseProtocol
136
+ attr_reader :max_string_size
137
137
 
138
- @@kJSONObjectStart = '{'
139
- @@kJSONObjectEnd = '}'
140
- @@kJSONArrayStart = '['
141
- @@kJSONArrayEnd = ']'
138
+ @@kJSONObjectStart = "{"
139
+ @@kJSONObjectEnd = "}"
140
+ @@kJSONArrayStart = "["
141
+ @@kJSONArrayEnd = "]"
142
142
  @@kJSONNewline = '\n'
143
- @@kJSONBackslash = '\\'
143
+ @@kJSONBackslash = "\\"
144
144
  @@kJSONStringDelimiter = '"'
145
145
 
146
146
  @@kThriftVersion1 = 1
@@ -149,8 +149,10 @@ module Thrift
149
149
  @@kThriftInfinity = "Infinity"
150
150
  @@kThriftNegativeInfinity = "-Infinity"
151
151
 
152
- def initialize(trans)
152
+ def initialize(trans, max_string_size: DEFAULT_MAX_STRING_SIZE)
153
+ BaseProtocol.validate_max_string_size(max_string_size)
153
154
  super(trans)
155
+ @max_string_size = max_string_size
154
156
  @context = JSONContext.new
155
157
  @contexts = Array.new
156
158
  @reader = LookaheadReader.new(trans)
@@ -183,42 +185,27 @@ module Thrift
183
185
  when Types::UUID
184
186
  "uid"
185
187
  else
186
- raise NotImplementedError
188
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Unknown type id: #{id}")
187
189
  end
188
190
  end
189
191
 
190
192
  def get_type_id_for_type_name(name)
191
- if (name == "tf")
192
- result = Types::BOOL
193
- elsif (name == "i8")
194
- result = Types::BYTE
195
- elsif (name == "i16")
196
- result = Types::I16
197
- elsif (name == "i32")
198
- result = Types::I32
199
- elsif (name == "i64")
200
- result = Types::I64
201
- elsif (name == "dbl")
202
- result = Types::DOUBLE
203
- elsif (name == "str")
204
- result = Types::STRING
205
- elsif (name == "rec")
206
- result = Types::STRUCT
207
- elsif (name == "map")
208
- result = Types::MAP
209
- elsif (name == "set")
210
- result = Types::SET
211
- elsif (name == "lst")
212
- result = Types::LIST
213
- elsif (name == "uid")
214
- result = Types::UUID
193
+ case name
194
+ when "tf" then Types::BOOL
195
+ when "i8" then Types::BYTE
196
+ when "i16" then Types::I16
197
+ when "i32" then Types::I32
198
+ when "i64" then Types::I64
199
+ when "dbl" then Types::DOUBLE
200
+ when "str" then Types::STRING
201
+ when "rec" then Types::STRUCT
202
+ when "map" then Types::MAP
203
+ when "set" then Types::SET
204
+ when "lst" then Types::LIST
205
+ when "uid" then Types::UUID
215
206
  else
216
- result = Types::STOP
217
- end
218
- if (result == Types::STOP)
219
- raise NotImplementedError
207
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Unknown type name: #{name.inspect}")
220
208
  end
221
- return result
222
209
  end
223
210
 
224
211
  # Static helper functions
@@ -228,17 +215,17 @@ module Thrift
228
215
  def self.read_syntax_char(reader, ch)
229
216
  ch2 = reader.read
230
217
  if (ch2 != ch)
231
- raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected \'#{ch}\' got \'#{ch2}\'.")
218
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected '#{ch}' got '#{ch2}'.")
232
219
  end
233
220
  end
234
221
 
235
- # Return true if the character ch is in [-+0-9.Ee]; false otherwise
222
+ # Return true if the character ch is in [-+0-9.Ee]; false otherwise
236
223
  def is_json_numeric(ch)
237
224
  case ch
238
- when '+', '-', '.', '0' .. '9', 'E', "e"
239
- return true
225
+ when "+", "-", ".", "0".."9", "E", "e"
226
+ true
240
227
  else
241
- return false
228
+ false
242
229
  end
243
230
  end
244
231
 
@@ -258,7 +245,7 @@ module Thrift
258
245
  if (ch_value.kind_of? String)
259
246
  ch_value = ch.bytes.first
260
247
  end
261
- trans.write(ch_value.to_s(16).rjust(4, '0'))
248
+ trans.write(ch_value.to_s(16).rjust(4, "0"))
262
249
  end
263
250
 
264
251
  # Write the character ch as part of a JSON string, escaping as appropriate.
@@ -268,10 +255,10 @@ module Thrift
268
255
  # 1 : just output index
269
256
  # <other> : escape using "\<other>" notation
270
257
  kJSONCharTable = [
271
- # 0 1 2 3 4 5 6 7 8 9 A B C D E F
272
- 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, # 0
273
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 1
274
- 1, 1, '"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 2
258
+ # 0 1 2 3 4 5 6 7 8 9 A B C D E F
259
+ 0, 0, 0, 0, 0, 0, 0, 0, "b", "t", "n", 0, "f", "r", 0, 0, # 0
260
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 1
261
+ 1, 1, '"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 2
275
262
  ]
276
263
 
277
264
  ch_value = ch[0]
@@ -301,9 +288,10 @@ module Thrift
301
288
 
302
289
  # Write out the contents of the string str as a JSON string, escaping characters as appropriate.
303
290
  def write_json_string(str)
291
+ str = normalize_json_string(str)
304
292
  @context.write(trans)
305
293
  trans.write(@@kJSONStringDelimiter)
306
- str.split('').each do |ch|
294
+ str.each_char do |ch|
307
295
  write_json_char(ch)
308
296
  end
309
297
  trans.write(@@kJSONStringDelimiter)
@@ -314,7 +302,7 @@ module Thrift
314
302
  def write_json_base64(str)
315
303
  @context.write(trans)
316
304
  trans.write(@@kJSONStringDelimiter)
317
- trans.write([str].pack('m0'))
305
+ trans.write([str].pack("m0"))
318
306
  trans.write(@@kJSONStringDelimiter)
319
307
  end
320
308
 
@@ -323,11 +311,11 @@ module Thrift
323
311
  def write_json_integer(num)
324
312
  @context.write(trans)
325
313
  escapeNum = @context.escapeNum
326
- if (escapeNum)
314
+ if escapeNum
327
315
  trans.write(@@kJSONStringDelimiter)
328
316
  end
329
317
  trans.write(num.to_s);
330
- if (escapeNum)
318
+ if escapeNum
331
319
  trans.write(@@kJSONStringDelimiter)
332
320
  end
333
321
  end
@@ -338,10 +326,10 @@ module Thrift
338
326
  @context.write(trans)
339
327
  # Normalize output of thrift::to_string for NaNs and Infinities
340
328
  special = false;
341
- if (num.nan?)
329
+ if num.nan?
342
330
  special = true;
343
331
  val = @@kThriftNan;
344
- elsif (num.infinite?)
332
+ elsif num.infinite?
345
333
  special = true;
346
334
  val = @@kThriftInfinity;
347
335
  if (num < 0.0)
@@ -352,11 +340,11 @@ module Thrift
352
340
  end
353
341
 
354
342
  escapeNum = special || @context.escapeNum
355
- if (escapeNum)
343
+ if escapeNum
356
344
  trans.write(@@kJSONStringDelimiter)
357
345
  end
358
346
  trans.write(val)
359
- if (escapeNum)
347
+ if escapeNum
360
348
  trans.write(@@kJSONStringDelimiter)
361
349
  end
362
350
  end
@@ -494,58 +482,65 @@ module Thrift
494
482
  JsonProtocol::read_syntax_char(@reader, ch)
495
483
  end
496
484
 
497
- # Decodes the four hex parts of a JSON escaped string character and returns
498
- # the character via out.
499
- #
500
- # Note - this only supports Unicode characters in the BMP (U+0000 to U+FFFF);
501
- # characters above the BMP are encoded as two escape sequences (surrogate pairs),
502
- # which is not yet implemented
503
485
  def read_json_escape_char
504
- str = +@reader.read
505
- str << @reader.read
506
- str << @reader.read
507
- str << @reader.read
508
- str.hex.chr(Encoding::UTF_8)
486
+ code_unit = read_unicode_code_unit
487
+
488
+ if code_unit.between?(0xD800, 0xDBFF)
489
+ slash = @reader.read
490
+ marker = @reader.read
491
+ invalid_unicode!("Unpaired UTF-16 high surrogate") unless slash == "\\" && marker == "u"
492
+
493
+ low_surrogate = read_unicode_code_unit
494
+ invalid_unicode!("Unpaired UTF-16 high surrogate") unless low_surrogate.between?(0xDC00, 0xDFFF)
495
+ codepoint = 0x10000 + ((code_unit - 0xD800) << 10) + (low_surrogate - 0xDC00)
496
+ [codepoint].pack("U")
497
+ elsif code_unit.between?(0xDC00, 0xDFFF)
498
+ invalid_unicode!("Unpaired UTF-16 low surrogate")
499
+ else
500
+ [code_unit].pack("U")
501
+ end
502
+ rescue EOFError
503
+ invalid_unicode!("Incomplete Unicode escape")
509
504
  end
510
505
 
511
506
  # Decodes a JSON string, including unescaping, and returns the string via str
512
507
  def read_json_string(skipContext = false)
513
508
  # This string's characters must match up with the elements in escape_char_vals.
514
- # I don't have '/' on this list even though it appears on www.json.org --
515
- # it is not in the RFC -> it is. See RFC 4627
509
+ # JSON permits the optional solidus escape "\/"; see RFC 8259, section 7.
516
510
  escape_chars = "\"\\/bfnrt"
517
511
 
518
512
  # The elements of this array must match up with the sequence of characters in
519
513
  # escape_chars
520
514
  escape_char_vals = [
521
- "\"", "\\", "\/", "\b", "\f", "\n", "\r", "\t",
515
+ "\"", "\\", "/", "\b", "\f", "\n", "\r", "\t",
522
516
  ]
523
517
 
524
518
  if !skipContext
525
519
  @context.read(@reader)
526
520
  end
527
521
  read_json_syntax_char(@@kJSONStringDelimiter)
528
- str = +''
529
- while (true)
522
+ str = Bytes.empty_byte_buffer
523
+ while true
530
524
  ch = @reader.read
531
525
  if (ch == @@kJSONStringDelimiter)
532
526
  break
533
527
  end
534
528
  if (ch == @@kJSONBackslash)
535
529
  ch = @reader.read
536
- if (ch == 'u')
530
+ if (ch == "u")
537
531
  ch = read_json_escape_char
538
532
  else
539
533
  pos = escape_chars.index(ch);
540
- if (pos.nil?) # not found
541
- raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected control char, got \'#{ch}\'.")
534
+ if pos.nil? # not found
535
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected control char, got '#{ch}'.")
542
536
  end
543
537
  ch = escape_char_vals[pos]
544
538
  end
545
539
  end
546
- str << ch
540
+ str << Bytes.force_binary_encoding(ch)
541
+ check_string_size(str.bytesize)
547
542
  end
548
- return str
543
+ decode_json_string(str)
549
544
  end
550
545
 
551
546
  # Reads a block of base64 characters, decoding it, and returns via str
@@ -555,32 +550,37 @@ module Thrift
555
550
  if m != 0
556
551
  # Add missing padding
557
552
  (4 - m).times do
558
- str += '='
553
+ str += "="
559
554
  end
560
555
  end
561
- str.unpack1('m0')
556
+ begin
557
+ str.unpack1("m0")
558
+ rescue ArgumentError
559
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Invalid Base64 data")
560
+ end
562
561
  end
563
562
 
564
563
  # Reads a sequence of characters, stopping at the first one that is not
565
564
  # a valid JSON numeric character.
566
565
  def read_json_numeric_chars
567
566
  str = String.new(encoding: Encoding::UTF_8)
568
- while (true)
567
+ while true
569
568
  ch = @reader.peek
570
- if (!is_json_numeric(ch))
569
+ if !is_json_numeric(ch)
571
570
  break;
572
571
  end
573
572
  ch = @reader.read
574
573
  str << ch
574
+ check_string_size(str.bytesize)
575
575
  end
576
- return str
576
+ str
577
577
  end
578
578
 
579
579
  # Reads a sequence of characters and assembles them into a number,
580
580
  # returning them via num
581
581
  def read_json_integer
582
582
  @context.read(@reader)
583
- if (@context.escapeNum)
583
+ if @context.escapeNum
584
584
  read_json_syntax_char(@@kJSONStringDelimiter)
585
585
  end
586
586
  str = read_json_numeric_chars
@@ -591,11 +591,11 @@ module Thrift
591
591
  raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected numeric value; got \"#{str}\"")
592
592
  end
593
593
 
594
- if (@context.escapeNum)
594
+ if @context.escapeNum
595
595
  read_json_syntax_char(@@kJSONStringDelimiter)
596
596
  end
597
597
 
598
- return num
598
+ num
599
599
  end
600
600
 
601
601
  # Reads a JSON number or string and interprets it as a double.
@@ -606,13 +606,13 @@ module Thrift
606
606
  str = read_json_string(true)
607
607
  # Check for NaN, Infinity and -Infinity
608
608
  if (str == @@kThriftNan)
609
- num = (+1.0/0.0)/(+1.0/0.0)
609
+ num = (+1.0 / 0.0) / (+1.0 / 0.0)
610
610
  elsif (str == @@kThriftInfinity)
611
- num = +1.0/0.0
611
+ num = +1.0 / 0.0
612
612
  elsif (str == @@kThriftNegativeInfinity)
613
- num = -1.0/0.0
613
+ num = -1.0 / 0.0
614
614
  else
615
- if (!@context.escapeNum)
615
+ if !@context.escapeNum
616
616
  # Raise exception -- we should not be in a string in this case
617
617
  raise ProtocolException.new(ProtocolException::INVALID_DATA, "Numeric data unexpectedly quoted")
618
618
  end
@@ -623,7 +623,7 @@ module Thrift
623
623
  end
624
624
  end
625
625
  else
626
- if (@context.escapeNum)
626
+ if @context.escapeNum
627
627
  # This will throw - we should have had a quote if escapeNum == true
628
628
  read_json_syntax_char(@@kJSONStringDelimiter)
629
629
  end
@@ -634,7 +634,7 @@ module Thrift
634
634
  raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected numeric value; got \"#{str}\"")
635
635
  end
636
636
  end
637
- return num
637
+ num
638
638
  end
639
639
 
640
640
  def read_json_object_start
@@ -667,7 +667,7 @@ module Thrift
667
667
  read_json_array_start
668
668
  version = read_json_integer
669
669
  if (version != @@kThriftVersion1)
670
- raise ProtocolException.new(ProtocolException::BAD_VERSION, 'Message contained bad version.')
670
+ raise ProtocolException.new(ProtocolException::BAD_VERSION, "Message contained bad version.")
671
671
  end
672
672
  name = read_json_string
673
673
  message_type = read_json_integer
@@ -779,21 +779,63 @@ module Thrift
779
779
  read_json_base64
780
780
  end
781
781
 
782
+ def skip_string
783
+ read_string
784
+ end
785
+
782
786
  def read_uuid
783
787
  uuid = read_json_string
784
- raise EOFError.new if uuid.length < 36
785
788
  UUID.validate_uuid!(uuid)
786
789
  uuid.tap(&:downcase!)
787
790
  end
788
791
 
789
792
  def to_s
790
- "json(#{super.to_s})"
793
+ "json(#{super})"
794
+ end
795
+
796
+ private
797
+
798
+ def normalize_json_string(str)
799
+ utf8 = if str.encoding == Encoding::UTF_8
800
+ str
801
+ elsif str.encoding == Encoding::BINARY
802
+ str.ascii_only? ? str : str.dup.force_encoding(Encoding::UTF_8)
803
+ else
804
+ str.encode(Encoding::UTF_8)
805
+ end
806
+ invalid_unicode!("Invalid UTF-8 string") unless utf8.valid_encoding?
807
+ utf8
808
+ rescue EncodingError
809
+ invalid_unicode!("Invalid UTF-8 string")
810
+ end
811
+
812
+ def decode_json_string(bytes)
813
+ bytes.force_encoding(Encoding::UTF_8)
814
+ invalid_unicode!("Invalid UTF-8 string") unless bytes.valid_encoding?
815
+ bytes
816
+ end
817
+
818
+ def read_unicode_code_unit
819
+ hex = Bytes.empty_byte_buffer
820
+ 4.times { hex << @reader.read }
821
+ invalid_unicode!("Invalid Unicode escape") unless hex.match?(/\A[0-9a-fA-F]{4}\z/)
822
+ hex.to_i(16)
823
+ rescue EOFError
824
+ invalid_unicode!("Incomplete Unicode escape")
825
+ end
826
+
827
+ def invalid_unicode!(message)
828
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, message)
791
829
  end
792
830
  end
793
831
 
794
832
  class JsonProtocolFactory < BaseProtocolFactory
833
+ def initialize(max_string_size: BaseProtocol::DEFAULT_MAX_STRING_SIZE)
834
+ @max_string_size = max_string_size
835
+ end
836
+
795
837
  def get_protocol(trans)
796
- return Thrift::JsonProtocol.new(trans)
838
+ Thrift::JsonProtocol.new(trans, max_string_size: @max_string_size)
797
839
  end
798
840
 
799
841
  def to_s
@@ -17,11 +17,10 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
- require 'thrift/protocol/protocol_decorator'
20
+ require "thrift/protocol/protocol_decorator"
21
21
 
22
22
  module Thrift
23
23
  class MultiplexedProtocol < BaseProtocol
24
-
25
24
  include ProtocolDecorator
26
25
 
27
26
  def initialize(protocol, service_name)
@@ -39,7 +38,7 @@ module Thrift
39
38
  end
40
39
 
41
40
  def to_s
42
- "multiplexed(#{@service_name=@protocol.to_s})"
41
+ "multiplexed(#{@protocol})"
43
42
  end
44
43
  end
45
44
  end
@@ -19,7 +19,6 @@
19
19
 
20
20
  module Thrift
21
21
  module ProtocolDecorator
22
-
23
22
  def initialize(protocol)
24
23
  @protocol = protocol
25
24
  end
@@ -29,7 +28,7 @@ module Thrift
29
28
  end
30
29
 
31
30
  def write_message_begin(name, type, seqid)
32
- @protocol.write_message_begin
31
+ @protocol.write_message_begin(name, type, seqid)
33
32
  end
34
33
 
35
34
  def write_message_end
@@ -196,6 +195,10 @@ module Thrift
196
195
  @protocol.read_binary
197
196
  end
198
197
 
198
+ def skip_string
199
+ @protocol.skip_string
200
+ end
201
+
199
202
  def read_uuid
200
203
  @protocol.read_uuid
201
204
  end
@@ -21,14 +21,20 @@
21
21
  module Thrift
22
22
  class Serializer
23
23
  def initialize(protocol_factory = BinaryProtocolFactory.new)
24
+ @protocol_factory = protocol_factory
24
25
  @transport = MemoryBufferTransport.new
25
26
  @protocol = protocol_factory.get_protocol(@transport)
26
27
  end
27
28
 
28
29
  def serialize(base)
29
30
  @transport.reset_buffer
31
+ @protocol ||= @protocol_factory.get_protocol(@transport)
30
32
  base.write(@protocol)
33
+ @protocol.trans.flush
31
34
  @transport.read(@transport.available)
35
+ rescue
36
+ @protocol = nil
37
+ raise
32
38
  end
33
39
  end
34
40
  end
@@ -18,13 +18,21 @@
18
18
  # under the License.
19
19
  #
20
20
 
21
+ require "logger"
22
+
21
23
  module Thrift
22
24
  class BaseServer
23
- def initialize(processor, server_transport, transport_factory = nil, protocol_factory = nil)
25
+ def initialize(processor, server_transport, transport_factory = nil, protocol_factory = nil, logger: nil)
24
26
  @processor = processor
25
27
  @server_transport = server_transport
26
28
  @transport_factory = transport_factory ? transport_factory : Thrift::BaseTransportFactory.new
27
29
  @protocol_factory = protocol_factory ? protocol_factory : Thrift::BinaryProtocolFactory.new
30
+ if logger.nil?
31
+ @logger = Logger.new(STDERR)
32
+ @logger.level = Logger::WARN
33
+ else
34
+ @logger = logger
35
+ end
28
36
  end
29
37
 
30
38
  def serve
@@ -32,7 +40,7 @@ module Thrift
32
40
  end
33
41
 
34
42
  def to_s
35
- "server(#{@protocol_factory.to_s}(#{@transport_factory.to_s}(#{@server_transport.to_s})))"
43
+ "server(#{@protocol_factory}(#{@transport_factory}(#{@server_transport})))"
36
44
  end
37
45
  end
38
46
  end