thrift 0.23.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 +203 -40
  3. data/ext/binary_protocol_accelerated.c +130 -40
  4. data/ext/bytes.c +14 -0
  5. data/ext/compact_protocol.c +184 -91
  6. data/ext/constants.h +3 -0
  7. data/ext/extconf.rb +12 -4
  8. data/ext/macros.h +11 -0
  9. data/ext/memory_buffer.c +67 -12
  10. data/ext/struct.c +192 -71
  11. data/ext/thrift_native.c +7 -0
  12. data/lib/thrift/bytes.rb +6 -3
  13. data/lib/thrift/client.rb +31 -33
  14. data/lib/thrift/exceptions.rb +11 -8
  15. data/lib/thrift/multiplexed_processor.rb +17 -8
  16. data/lib/thrift/processor.rb +25 -3
  17. data/lib/thrift/protocol/base_protocol.rb +66 -31
  18. data/lib/thrift/protocol/binary_protocol.rb +80 -37
  19. data/lib/thrift/protocol/binary_protocol_accelerated.rb +7 -2
  20. data/lib/thrift/protocol/compact_protocol.rb +204 -88
  21. data/lib/thrift/protocol/header_protocol.rb +15 -3
  22. data/lib/thrift/protocol/json_protocol.rb +158 -109
  23. data/lib/thrift/protocol/multiplexed_protocol.rb +3 -3
  24. data/lib/thrift/protocol/protocol_decorator.rb +6 -2
  25. data/lib/thrift/serializer/deserializer.rb +1 -0
  26. data/lib/thrift/serializer/serializer.rb +7 -0
  27. data/lib/thrift/server/base_server.rb +11 -2
  28. data/lib/thrift/server/nonblocking_server.rb +69 -20
  29. data/lib/thrift/server/rack_application.rb +69 -0
  30. data/lib/thrift/server/simple_server.rb +27 -15
  31. data/lib/thrift/server/thin_http_server.rb +21 -44
  32. data/lib/thrift/server/thread_pool_server.rb +21 -17
  33. data/lib/thrift/server/threaded_server.rb +22 -18
  34. data/lib/thrift/struct.rb +34 -18
  35. data/lib/thrift/struct_union.rb +37 -36
  36. data/lib/thrift/thrift_native.rb +2 -1
  37. data/lib/thrift/transport/base_server_transport.rb +3 -0
  38. data/lib/thrift/transport/base_transport.rb +26 -4
  39. data/lib/thrift/transport/buffered_transport.rb +5 -4
  40. data/lib/thrift/transport/framed_transport.rb +33 -7
  41. data/lib/thrift/transport/header_transport.rb +159 -33
  42. data/lib/thrift/transport/http_client_transport.rb +28 -14
  43. data/lib/thrift/transport/io_stream_transport.rb +3 -1
  44. data/lib/thrift/transport/memory_buffer_transport.rb +14 -9
  45. data/lib/thrift/transport/server_socket.rb +10 -8
  46. data/lib/thrift/transport/socket.rb +85 -48
  47. data/lib/thrift/transport/ssl_server_socket.rb +67 -6
  48. data/lib/thrift/transport/ssl_socket.rb +73 -14
  49. data/lib/thrift/transport/unix_server_socket.rb +6 -2
  50. data/lib/thrift/transport/unix_socket.rb +5 -6
  51. data/lib/thrift/types.rb +23 -22
  52. data/lib/thrift/union.rb +21 -11
  53. data/lib/thrift/uuid.rb +9 -8
  54. data/lib/thrift.rb +40 -39
  55. metadata +7 -266
  56. data/benchmark/Benchmark.thrift +0 -24
  57. data/benchmark/benchmark.rb +0 -285
  58. data/benchmark/client.rb +0 -117
  59. data/benchmark/server.rb +0 -120
  60. data/benchmark/thin_server.rb +0 -45
  61. data/lib/thrift/server/mongrel_http_server.rb +0 -60
  62. data/spec/BaseService.thrift +0 -27
  63. data/spec/ExtendedService.thrift +0 -25
  64. data/spec/Referenced.thrift +0 -44
  65. data/spec/ThriftNamespacedSpec.thrift +0 -53
  66. data/spec/ThriftSpec.thrift +0 -187
  67. data/spec/base_protocol_spec.rb +0 -224
  68. data/spec/base_transport_spec.rb +0 -387
  69. data/spec/binary_protocol_accelerated_spec.rb +0 -46
  70. data/spec/binary_protocol_spec.rb +0 -72
  71. data/spec/binary_protocol_spec_shared.rb +0 -445
  72. data/spec/bytes_spec.rb +0 -99
  73. data/spec/client_spec.rb +0 -166
  74. data/spec/compact_protocol_spec.rb +0 -196
  75. data/spec/constants_demo_spec.rb +0 -101
  76. data/spec/exception_spec.rb +0 -140
  77. data/spec/flat_spec.rb +0 -62
  78. data/spec/header_protocol_spec.rb +0 -475
  79. data/spec/header_transport_spec.rb +0 -386
  80. data/spec/http_client_spec.rb +0 -159
  81. data/spec/json_protocol_spec.rb +0 -552
  82. data/spec/namespaced_spec.rb +0 -66
  83. data/spec/nonblocking_server_spec.rb +0 -361
  84. data/spec/processor_spec.rb +0 -79
  85. data/spec/serializer_spec.rb +0 -66
  86. data/spec/server_socket_spec.rb +0 -84
  87. data/spec/server_spec.rb +0 -186
  88. data/spec/socket_spec.rb +0 -67
  89. data/spec/socket_spec_shared.rb +0 -167
  90. data/spec/spec_helper.rb +0 -69
  91. data/spec/ssl_server_socket_spec.rb +0 -45
  92. data/spec/ssl_socket_spec.rb +0 -87
  93. data/spec/struct_nested_containers_spec.rb +0 -190
  94. data/spec/struct_spec.rb +0 -397
  95. data/spec/support/header_protocol_helper.rb +0 -54
  96. data/spec/thin_http_server_spec.rb +0 -126
  97. data/spec/types_spec.rb +0 -117
  98. data/spec/union_spec.rb +0 -272
  99. data/spec/unix_socket_spec.rb +0 -115
  100. data/spec/uuid_validation_spec.rb +0 -238
  101. data/test/fuzz/Makefile.am +0 -173
  102. data/test/fuzz/README.md +0 -149
  103. data/test/fuzz/fuzz_common.rb +0 -95
  104. data/test/fuzz/fuzz_parse_binary_protocol.rb +0 -22
  105. data/test/fuzz/fuzz_parse_binary_protocol_accelerated.rb +0 -22
  106. data/test/fuzz/fuzz_parse_binary_protocol_accelerated_harness.rb +0 -22
  107. data/test/fuzz/fuzz_parse_binary_protocol_harness.rb +0 -22
  108. data/test/fuzz/fuzz_parse_compact_protocol.rb +0 -22
  109. data/test/fuzz/fuzz_parse_compact_protocol_harness.rb +0 -22
  110. data/test/fuzz/fuzz_parse_json_protocol.rb +0 -22
  111. data/test/fuzz/fuzz_parse_json_protocol_harness.rb +0 -22
  112. data/test/fuzz/fuzz_roundtrip_binary_protocol.rb +0 -22
  113. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated.rb +0 -22
  114. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated_harness.rb +0 -22
  115. data/test/fuzz/fuzz_roundtrip_binary_protocol_harness.rb +0 -22
  116. data/test/fuzz/fuzz_roundtrip_compact_protocol.rb +0 -22
  117. data/test/fuzz/fuzz_roundtrip_compact_protocol_harness.rb +0 -22
  118. data/test/fuzz/fuzz_roundtrip_json_protocol.rb +0 -22
  119. data/test/fuzz/fuzz_roundtrip_json_protocol_harness.rb +0 -22
  120. data/test/fuzz/fuzz_tracer.rb +0 -28
@@ -1,4 +1,5 @@
1
1
  # encoding: UTF-8
2
+ # frozen_string_literal: true
2
3
  #
3
4
  # Licensed to the Apache Software Foundation (ASF) under one
4
5
  # or more contributor license agreements. See the NOTICE file
@@ -33,7 +34,7 @@ module Thrift
33
34
  @data = @trans.read(1)
34
35
  end
35
36
 
36
- return @data
37
+ @data
37
38
  end
38
39
 
39
40
  def peek
@@ -41,7 +42,7 @@ module Thrift
41
42
  @data = @trans.read(1)
42
43
  end
43
44
  @hasData = true
44
- return @data
45
+ @data
45
46
  end
46
47
  end
47
48
 
@@ -50,7 +51,7 @@ module Thrift
50
51
  # implementations
51
52
  #
52
53
  class JSONContext
53
- @@kJSONElemSeparator = ','
54
+ @@kJSONElemSeparator = ","
54
55
  #
55
56
  # Write context data to the trans. Default is to do nothing.
56
57
  #
@@ -68,13 +69,13 @@ module Thrift
68
69
  # Default behavior is to return false.
69
70
  #
70
71
  def escapeNum
71
- return false
72
+ false
72
73
  end
73
74
  end
74
75
 
75
76
  # Context class for object member key-value pairs
76
77
  class JSONPairContext < JSONContext
77
- @@kJSONPairSeparator = ':'
78
+ @@kJSONPairSeparator = ":"
78
79
 
79
80
  def initialize
80
81
  @first = true
@@ -82,7 +83,7 @@ module Thrift
82
83
  end
83
84
 
84
85
  def write(trans)
85
- if (@first)
86
+ if @first
86
87
  @first = false
87
88
  @colon = true
88
89
  else
@@ -92,7 +93,7 @@ module Thrift
92
93
  end
93
94
 
94
95
  def read(reader)
95
- if (@first)
96
+ if @first
96
97
  @first = false
97
98
  @colon = true
98
99
  else
@@ -104,19 +105,18 @@ module Thrift
104
105
 
105
106
  # Numbers must be turned into strings if they are the key part of a pair
106
107
  def escapeNum
107
- return @colon
108
+ @colon
108
109
  end
109
110
  end
110
111
 
111
112
  # Context class for lists
112
113
  class JSONListContext < JSONContext
113
-
114
114
  def initialize
115
115
  @first = true
116
116
  end
117
117
 
118
118
  def write(trans)
119
- if (@first)
119
+ if @first
120
120
  @first = false
121
121
  else
122
122
  trans.write(@@kJSONElemSeparator)
@@ -124,7 +124,7 @@ module Thrift
124
124
  end
125
125
 
126
126
  def read(reader)
127
- if (@first)
127
+ if @first
128
128
  @first = false
129
129
  else
130
130
  JsonProtocol::read_syntax_char(reader, @@kJSONElemSeparator)
@@ -133,13 +133,14 @@ module Thrift
133
133
  end
134
134
 
135
135
  class JsonProtocol < BaseProtocol
136
+ attr_reader :max_string_size
136
137
 
137
- @@kJSONObjectStart = '{'
138
- @@kJSONObjectEnd = '}'
139
- @@kJSONArrayStart = '['
140
- @@kJSONArrayEnd = ']'
138
+ @@kJSONObjectStart = "{"
139
+ @@kJSONObjectEnd = "}"
140
+ @@kJSONArrayStart = "["
141
+ @@kJSONArrayEnd = "]"
141
142
  @@kJSONNewline = '\n'
142
- @@kJSONBackslash = '\\'
143
+ @@kJSONBackslash = "\\"
143
144
  @@kJSONStringDelimiter = '"'
144
145
 
145
146
  @@kThriftVersion1 = 1
@@ -148,8 +149,10 @@ module Thrift
148
149
  @@kThriftInfinity = "Infinity"
149
150
  @@kThriftNegativeInfinity = "-Infinity"
150
151
 
151
- def initialize(trans)
152
+ def initialize(trans, max_string_size: DEFAULT_MAX_STRING_SIZE)
153
+ BaseProtocol.validate_max_string_size(max_string_size)
152
154
  super(trans)
155
+ @max_string_size = max_string_size
153
156
  @context = JSONContext.new
154
157
  @contexts = Array.new
155
158
  @reader = LookaheadReader.new(trans)
@@ -182,42 +185,27 @@ module Thrift
182
185
  when Types::UUID
183
186
  "uid"
184
187
  else
185
- raise NotImplementedError
188
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Unknown type id: #{id}")
186
189
  end
187
190
  end
188
191
 
189
192
  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
- elsif (name == "uid")
213
- 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
214
206
  else
215
- result = Types::STOP
207
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Unknown type name: #{name.inspect}")
216
208
  end
217
- if (result == Types::STOP)
218
- raise NotImplementedError
219
- end
220
- return result
221
209
  end
222
210
 
223
211
  # Static helper functions
@@ -227,17 +215,17 @@ module Thrift
227
215
  def self.read_syntax_char(reader, ch)
228
216
  ch2 = reader.read
229
217
  if (ch2 != ch)
230
- raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected \'#{ch}\' got \'#{ch2}\'.")
218
+ raise ProtocolException.new(ProtocolException::INVALID_DATA, "Expected '#{ch}' got '#{ch2}'.")
231
219
  end
232
220
  end
233
221
 
234
- # 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
235
223
  def is_json_numeric(ch)
236
224
  case ch
237
- when '+', '-', '.', '0' .. '9', 'E', "e"
238
- return true
225
+ when "+", "-", ".", "0".."9", "E", "e"
226
+ true
239
227
  else
240
- return false
228
+ false
241
229
  end
242
230
  end
243
231
 
@@ -257,7 +245,7 @@ module Thrift
257
245
  if (ch_value.kind_of? String)
258
246
  ch_value = ch.bytes.first
259
247
  end
260
- trans.write(ch_value.to_s(16).rjust(4, '0'))
248
+ trans.write(ch_value.to_s(16).rjust(4, "0"))
261
249
  end
262
250
 
263
251
  # Write the character ch as part of a JSON string, escaping as appropriate.
@@ -267,10 +255,10 @@ module Thrift
267
255
  # 1 : just output index
268
256
  # <other> : escape using "\<other>" notation
269
257
  kJSONCharTable = [
270
- # 0 1 2 3 4 5 6 7 8 9 A B C D E F
271
- 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, # 0
272
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 1
273
- 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
274
262
  ]
275
263
 
276
264
  ch_value = ch[0]
@@ -300,9 +288,10 @@ module Thrift
300
288
 
301
289
  # Write out the contents of the string str as a JSON string, escaping characters as appropriate.
302
290
  def write_json_string(str)
291
+ str = normalize_json_string(str)
303
292
  @context.write(trans)
304
293
  trans.write(@@kJSONStringDelimiter)
305
- str.split('').each do |ch|
294
+ str.each_char do |ch|
306
295
  write_json_char(ch)
307
296
  end
308
297
  trans.write(@@kJSONStringDelimiter)
@@ -313,7 +302,7 @@ module Thrift
313
302
  def write_json_base64(str)
314
303
  @context.write(trans)
315
304
  trans.write(@@kJSONStringDelimiter)
316
- trans.write([str].pack('m0'))
305
+ trans.write([str].pack("m0"))
317
306
  trans.write(@@kJSONStringDelimiter)
318
307
  end
319
308
 
@@ -322,11 +311,11 @@ module Thrift
322
311
  def write_json_integer(num)
323
312
  @context.write(trans)
324
313
  escapeNum = @context.escapeNum
325
- if (escapeNum)
314
+ if escapeNum
326
315
  trans.write(@@kJSONStringDelimiter)
327
316
  end
328
317
  trans.write(num.to_s);
329
- if (escapeNum)
318
+ if escapeNum
330
319
  trans.write(@@kJSONStringDelimiter)
331
320
  end
332
321
  end
@@ -337,10 +326,10 @@ module Thrift
337
326
  @context.write(trans)
338
327
  # Normalize output of thrift::to_string for NaNs and Infinities
339
328
  special = false;
340
- if (num.nan?)
329
+ if num.nan?
341
330
  special = true;
342
331
  val = @@kThriftNan;
343
- elsif (num.infinite?)
332
+ elsif num.infinite?
344
333
  special = true;
345
334
  val = @@kThriftInfinity;
346
335
  if (num < 0.0)
@@ -351,11 +340,11 @@ module Thrift
351
340
  end
352
341
 
353
342
  escapeNum = special || @context.escapeNum
354
- if (escapeNum)
343
+ if escapeNum
355
344
  trans.write(@@kJSONStringDelimiter)
356
345
  end
357
346
  trans.write(val)
358
- if (escapeNum)
347
+ if escapeNum
359
348
  trans.write(@@kJSONStringDelimiter)
360
349
  end
361
350
  end
@@ -493,59 +482,65 @@ module Thrift
493
482
  JsonProtocol::read_syntax_char(@reader, ch)
494
483
  end
495
484
 
496
- # Decodes the four hex parts of a JSON escaped string character and returns
497
- # the character via out.
498
- #
499
- # Note - this only supports Unicode characters in the BMP (U+0000 to U+FFFF);
500
- # characters above the BMP are encoded as two escape sequences (surrogate pairs),
501
- # which is not yet implemented
502
485
  def read_json_escape_char
503
- str = @reader.read
504
- str += @reader.read
505
- str += @reader.read
506
- str += @reader.read
507
- 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")
508
504
  end
509
505
 
510
506
  # Decodes a JSON string, including unescaping, and returns the string via str
511
507
  def read_json_string(skipContext = false)
512
508
  # This string's characters must match up with the elements in escape_char_vals.
513
- # I don't have '/' on this list even though it appears on www.json.org --
514
- # it is not in the RFC -> it is. See RFC 4627
509
+ # JSON permits the optional solidus escape "\/"; see RFC 8259, section 7.
515
510
  escape_chars = "\"\\/bfnrt"
516
511
 
517
512
  # The elements of this array must match up with the sequence of characters in
518
513
  # escape_chars
519
514
  escape_char_vals = [
520
- "\"", "\\", "\/", "\b", "\f", "\n", "\r", "\t",
515
+ "\"", "\\", "/", "\b", "\f", "\n", "\r", "\t",
521
516
  ]
522
517
 
523
518
  if !skipContext
524
519
  @context.read(@reader)
525
520
  end
526
521
  read_json_syntax_char(@@kJSONStringDelimiter)
527
- ch = ""
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
- str = ""
568
- while (true)
566
+ str = String.new(encoding: Encoding::UTF_8)
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
- str += ch
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
@@ -712,6 +712,7 @@ module Thrift
712
712
  key_type = get_type_id_for_type_name(read_json_string)
713
713
  val_type = get_type_id_for_type_name(read_json_string)
714
714
  size = read_json_integer
715
+ validate_container_size(size)
715
716
  read_json_object_start
716
717
  [key_type, val_type, size]
717
718
  end
@@ -723,7 +724,10 @@ module Thrift
723
724
 
724
725
  def read_list_begin
725
726
  read_json_array_start
726
- [get_type_id_for_type_name(read_json_string), read_json_integer]
727
+ type = get_type_id_for_type_name(read_json_string)
728
+ size = read_json_integer
729
+ validate_container_size(size)
730
+ [type, size]
727
731
  end
728
732
 
729
733
  def read_list_end
@@ -732,7 +736,10 @@ module Thrift
732
736
 
733
737
  def read_set_begin
734
738
  read_json_array_start
735
- [get_type_id_for_type_name(read_json_string), read_json_integer]
739
+ type = get_type_id_for_type_name(read_json_string)
740
+ size = read_json_integer
741
+ validate_container_size(size)
742
+ [type, size]
736
743
  end
737
744
 
738
745
  def read_set_end
@@ -772,21 +779,63 @@ module Thrift
772
779
  read_json_base64
773
780
  end
774
781
 
782
+ def skip_string
783
+ read_string
784
+ end
785
+
775
786
  def read_uuid
776
787
  uuid = read_json_string
777
- raise EOFError.new if uuid.length < 36
778
788
  UUID.validate_uuid!(uuid)
779
789
  uuid.tap(&:downcase!)
780
790
  end
781
791
 
782
792
  def to_s
783
- "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)
784
829
  end
785
830
  end
786
831
 
787
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
+
788
837
  def get_protocol(trans)
789
- return Thrift::JsonProtocol.new(trans)
838
+ Thrift::JsonProtocol.new(trans, max_string_size: @max_string_size)
790
839
  end
791
840
 
792
841
  def to_s
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # Licensed to the Apache Software Foundation (ASF) under one
3
4
  # or more contributor license agreements. See the NOTICE file
@@ -16,11 +17,10 @@
16
17
  # specific language governing permissions and limitations
17
18
  # under the License.
18
19
 
19
- require 'thrift/protocol/protocol_decorator'
20
+ require "thrift/protocol/protocol_decorator"
20
21
 
21
22
  module Thrift
22
23
  class MultiplexedProtocol < BaseProtocol
23
-
24
24
  include ProtocolDecorator
25
25
 
26
26
  def initialize(protocol, service_name)
@@ -38,7 +38,7 @@ module Thrift
38
38
  end
39
39
 
40
40
  def to_s
41
- "multiplexed(#{@service_name=@protocol.to_s})"
41
+ "multiplexed(#{@protocol})"
42
42
  end
43
43
  end
44
44
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # Licensed to the Apache Software Foundation (ASF) under one
3
4
  # or more contributor license agreements. See the NOTICE file
@@ -18,7 +19,6 @@
18
19
 
19
20
  module Thrift
20
21
  module ProtocolDecorator
21
-
22
22
  def initialize(protocol)
23
23
  @protocol = protocol
24
24
  end
@@ -28,7 +28,7 @@ module Thrift
28
28
  end
29
29
 
30
30
  def write_message_begin(name, type, seqid)
31
- @protocol.write_message_begin
31
+ @protocol.write_message_begin(name, type, seqid)
32
32
  end
33
33
 
34
34
  def write_message_end
@@ -195,6 +195,10 @@ module Thrift
195
195
  @protocol.read_binary
196
196
  end
197
197
 
198
+ def skip_string
199
+ @protocol.skip_string
200
+ end
201
+
198
202
  def read_uuid
199
203
  @protocol.read_uuid
200
204
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # Licensed to the Apache Software Foundation (ASF) under one
3
4
  # or more contributor license agreements. See the NOTICE file
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # Licensed to the Apache Software Foundation (ASF) under one
3
4
  # or more contributor license agreements. See the NOTICE file
@@ -20,14 +21,20 @@
20
21
  module Thrift
21
22
  class Serializer
22
23
  def initialize(protocol_factory = BinaryProtocolFactory.new)
24
+ @protocol_factory = protocol_factory
23
25
  @transport = MemoryBufferTransport.new
24
26
  @protocol = protocol_factory.get_protocol(@transport)
25
27
  end
26
28
 
27
29
  def serialize(base)
28
30
  @transport.reset_buffer
31
+ @protocol ||= @protocol_factory.get_protocol(@transport)
29
32
  base.write(@protocol)
33
+ @protocol.trans.flush
30
34
  @transport.read(@transport.available)
35
+ rescue
36
+ @protocol = nil
37
+ raise
31
38
  end
32
39
  end
33
40
  end